Compare commits

...

260 Commits

Author SHA1 Message Date
Jonathan Naylor ca76dfc728
Merge pull request #348 from k7pws/patch-2
Update NXDNHosts.txt
2024-02-17 17:50:31 +00:00
k7pws a8644497bb
Update NXDNHosts.txt
updated DNS and port inforamtion for 31490.
2024-02-16 22:28:54 -07:00
Jonathan Naylor 7b458b8afb Re-add IPv4 and IPv6 capability to the NXDN networking. 2024-01-29 19:35:59 +00:00
Jonathan Naylor 80a32f358f Remove unneeded define. 2024-01-29 16:17:53 +00:00
Jonathan Naylor 4cd7e99283 Simplify the UDP socket handling. 2024-01-29 16:00:25 +00:00
Jonathan Naylor cf804904f7
Merge pull request #346 from W4END/patch-2
Update NXDNHosts.txt
2024-01-26 15:50:36 +00:00
W4END e010f4e2fd
Update NXDNHosts.txt
Changed TG 805 to new IP address. 
45.32.166.46
2024-01-23 21:04:29 -06:00
Jonathan Naylor 54dcfded80
Merge pull request #345 from IU5HJU/patch-2
Update NXDNHosts.txt
2024-01-20 20:53:41 +00:00
Jonathan Naylor 2df088c3d5
Merge pull request #344 from W4END/patch-1
Update NXDNHosts.txt
2024-01-20 20:53:18 +00:00
Michele c60a8618dc
Update NXDNHosts.txt
PLS add Tuscany Reflector
2024-01-20 18:04:09 +01:00
W4END 6a8f84c666
Update NXDNHosts.txt
Adding line 81 and 82 as follows ...

# 805 US RocketCity-AL-NXDN Bridge
805 155.138.207.101 41400

Thanks W4END
2024-01-19 12:52:32 -06:00
Jonathan Naylor ccc4af8b75
Merge pull request #343 from maq1017/patch-1
Update NXDNHosts.txt
2024-01-02 14:04:02 +00:00
Jonathan Naylor 3b0d2c4a3a
Merge pull request #341 from kc1awv/patch-2
Update NXDNHosts.txt
2024-01-02 14:03:38 +00:00
maq1017 370c7c4465
Update NXDNHosts.txt
Updated 841 hostname
2023-12-30 16:56:34 +00:00
Steve Miller 09b7405c0e
Update NXDNHosts.txt
Update M17 URF Reflector
2023-12-12 16:40:11 -05:00
Jonathan Naylor a11d2b0dbb
Merge pull request #340 from dl9cma/patch-2
Update NXDNHosts.txt
2023-12-10 14:32:10 +00:00
dl9cma b8ec1b079a
Update NXDNHosts.txt
update DNS-Address for 26200 Reflector
2023-12-08 20:20:25 +01:00
Jonathan Naylor 6b4ac07a98
Merge pull request #337 from jjsainzc/patch-1
Update NXDNHosts.txt
2023-12-07 17:53:36 +00:00
Jonathan Naylor 7df53ae813
Merge pull request #336 from UR5WLA/patch-4
Update NXDNHosts.txt
2023-12-07 17:53:14 +00:00
Jorge Jesus Sainz Casalla 94e100f3b6
Update NXDNHosts.txt
Adding Ecuador reflector
2023-12-07 10:55:19 -05:00
UR5WLA e1e181da91
Update NXDNHosts.txt
# 25577 UA Azimuth
25577	nxdn.ur4wwr.org	41400
2023-11-29 22:58:52 +02:00
Jonathan Naylor 8e8bad4fff
Update NXDNHosts.txt 2023-11-28 19:09:00 +00:00
Jonathan Naylor a6b1c78a2d
Merge pull request #335 from PU5SMS/patch-2
Update NXDNHosts.txt
2023-11-28 19:07:40 +00:00
PU5SMS a8ee46e7f0
Update NXDNHosts.txt
Done... thanks!
2023-11-28 14:12:27 -03:00
Jonathan Naylor a805717730
Merge pull request #333 from Merlinv3/patch-22
Update NXDNHosts.txt
2023-11-28 16:48:49 +00:00
PU5SMS 451e51b4a4
Update NXDNHosts.txt
Request to add to NXDN reflector list.
2023-11-28 12:22:39 -03:00
Merlinv3 55d18fa10b
Update NXDNHosts.txt
Update NXDNHosts.txt
2023-11-26 16:38:22 +01:00
Jonathan Naylor 05b9990846
Merge pull request #329 from mfiscus/kk7mnz/add-848
Add 848
2023-11-20 16:45:15 +00:00
Matt Fiscus 65ff0c740c
Merge branch 'g4klx:master' into kk7mnz/add-848 2023-11-20 09:39:02 -07:00
Matt Fiscus e8d5d91680
Updated format for 848 in NXDNHosts.txt 2023-11-20 09:38:25 -07:00
Jonathan Naylor 8875e20570
Update NXDNHosts.txt 2023-11-20 15:28:40 +00:00
mfiscus 35a04a4472 Update NXDNHosts.txt 2023-11-19 14:50:34 -07:00
Jonathan Naylor 1f140d8e28
Merge pull request #328 from ds5qdr/patch-2
Update NXDNHosts.txt
2023-11-14 14:54:19 +00:00
Heonmin Lee 0746ded83b
Update NXDNHosts.txt
Good morning Jonathan

Please add the following host to the NXDN Hosts list

# 45001 NXDN-DS5QDR Korea
45001	ds5qdr-mst.duckdns.org	41400


Thank you for your help

DS5QDR Heonmin Lee from Korea
2023-11-14 22:13:25 +09:00
Jonathan Naylor d504e84738
Merge pull request #327 from M0JGX/patch-3
Update NXDNHosts.txt
2023-11-14 10:38:15 +00:00
M0JGX 0382d31ecc
Update NXDNHosts.txt
Updated the description for 235 and added 23556 as a UK wide multimode on the DVSPH system
2023-11-13 17:50:04 +00:00
Jonathan Naylor de3d1086c3 Only check the address on incoming Icom data. 2023-11-12 21:50:10 +00:00
Jonathan Naylor 843f12e2ca
Update NXDNHosts.txt 2023-11-11 22:02:05 +00:00
Jonathan Naylor 29e6bee0ec
Merge pull request #326 from N6DOZ/patch-5
Update NXDNHosts.txt
2023-11-11 21:50:29 +00:00
Rudy 5fdb97dc8d
Update NXDNHosts.txt
Added reflector 31177

# 31177 WESDIG Western US Digital Group
31177  nxdn.wesdig.com  41400
2023-11-11 12:39:12 -08:00
Jonathan Naylor 9c590e0009
Merge pull request #324 from skynetgwds/patch-1
Update NXDNHosts.txt
2023-10-25 17:13:41 +01:00
Gareth GM0WUR 4a2a68b494
Update NXDNHosts.txt
Request inclusion of new host for Extended Freedom Network #23525 nxdn.m0xfn.radio
2023-10-21 23:11:01 +01:00
Jonathan Naylor 501fce4113
Merge pull request #323 from ke8ane/patch-4
Update NXDNHosts.txt
2023-10-16 15:19:14 +01:00
ke8ane 6544ed151b
Update NXDNHosts.txt 2023-10-11 16:29:24 -04:00
Jonathan Naylor 674d9e2424
Merge pull request #322 from mfiscus/kk7mnz/update-847
Update NXDNHosts.txt update 847 URL
2023-09-27 09:50:46 +01:00
mfiscus e7bdf23822 Update NXDNHosts.txt 2023-09-26 18:13:54 -07:00
Jonathan Naylor e7316823af
Update NXDNHosts.txt 2023-09-26 14:00:59 +01:00
Jonathan Naylor 1a7804ed7f
Merge pull request #321 from W2GLD/patch-4
Update NXDNHosts.txt
2023-09-26 13:58:02 +01:00
Jonathan Naylor 78ec1b00f9
Merge pull request #319 from IU5HJU/patch-1
Update NXDNHosts.txt
2023-09-26 13:57:32 +01:00
W2GLD c23f238255
Update NXDNHosts.txt
Removed reflector that is no longer in-service #31266
2023-09-23 15:42:16 -04:00
Michele 930fc9a03d
Update NXDNHosts.txt
Delete TG 2225, TG 2241, mod. TG 22292
2023-09-19 10:42:09 +02:00
Jonathan Naylor 15730cd271
Merge pull request #318 from M0JGX/patch-2 2023-09-05 14:01:08 +01:00
M0JGX e553489ae5
Update NXDNHosts.txt 2023-09-05 10:44:33 +01:00
Jonathan Naylor 7abe7706bb
Update NXDNHosts.txt 2023-08-23 16:43:04 +01:00
Jonathan Naylor cfcaab90ba
Merge pull request #316 from mfiscus/master
Add 847
2023-08-20 13:35:40 +01:00
mfiscus bc08575976 Add 847
https://urf847.kk7mnz.com
2023-08-20 00:43:36 -07:00
Jonathan Naylor 2a83f19a1a
Update NXDNHosts.txt 2023-08-04 14:34:38 +01:00
Jonathan Naylor 83965095d5
Merge pull request #315 from dbehnke/dbehnke/add70777
add 70777 Who Cares ARG to host list
2023-07-05 11:39:32 +01:00
Dave Behnke 1138d26c87 change to 60777 Who Cares ARG to host list 2023-07-01 23:38:34 -04:00
Dave Behnke 2db8bcb31a add 70777 Who Cares ARG to host list 2023-07-01 12:56:00 -04:00
Jonathan Naylor 6b021c2f46
Merge pull request #314 from k7pws/patch-1
Update NXDNHosts.txt
2023-06-20 15:35:18 +01:00
k7pws 6d9764e43e
Update NXDNHosts.txt 2023-06-19 16:30:46 -06:00
Jonathan Naylor f798f99036
Merge pull request #313 from kd8grn/patch-1 2023-06-15 21:13:41 +01:00
kd8grn 7f01d3d6b2
Update NXDNHosts.txt
Added the new OhioLink NXDN reflector.
2023-06-15 14:02:25 -04:00
Jonathan Naylor 8d1dc5e145
Merge pull request #312 from ferjavrec/master 2023-06-14 11:49:21 +01:00
Fernando Recci 9f1c1ac884 I add TG 7221 in NXDNHosts.txt 2023-06-12 20:52:11 -03:00
Jonathan Naylor bef256b258
Merge pull request #311 from d3sl91/master
Update NXDNHosts.txt
2023-06-11 10:20:25 +01:00
Ethan Gollehon 2da36dad46
Update NXDNHosts.txt
Added HRCC Link #621
2023-06-10 22:05:38 -07:00
Jonathan Naylor 78eb626394
Merge pull request #310 from bh1nyr/master
Update NXDNHosts.txt
2023-06-05 22:31:20 +01:00
bh1nyr 4916ef66d5
Update NXDNHosts.txt 2023-06-06 01:17:09 +08:00
Jonathan Naylor e20e3a3387
Merge pull request #309 from M0JGX/patch-1 2023-06-04 11:55:14 +01:00
M0JGX 8da5e81596
Added 23556 - DVSPH Multimode 2023-06-04 11:50:20 +01:00
Jonathan Naylor dd193c5396
Merge pull request #308 from m0glj/patch-27 2023-06-03 19:24:26 +01:00
M0GLJ e006e492f2
Update NXDNHosts.txt
New Reflector
2023-06-03 18:51:30 +01:00
Jonathan Naylor c1d02c3396
Update NXDNHosts.txt 2023-05-28 10:37:31 +01:00
Jonathan Naylor 964ad926b9
Merge pull request #307 from vk3jed/patch-2 2023-05-26 09:31:25 +01:00
Tony Langdon 6ea9689870
Update NXDNHosts.txt
Added reflector 9517
2023-05-26 13:34:07 +10:00
Jonathan Naylor 46000902b2
Merge pull request #305 from f1rmb/f1rmb_gpsd_fix_status_check_api_version_2
Handle GPSd API version about fix status.
2023-05-21 12:56:29 +01:00
Jonathan Naylor 52ff3db788
Update NXDNHosts.txt 2023-05-21 12:55:43 +01:00
Daniel Caujolle-Bert f4914fe13c Handle GPSd API version about fix status. 2023-05-21 07:50:01 +02:00
Jonathan Naylor 90dec58610
Merge pull request #303 from W0CHP/master
Update sample INI with quoted `Symbol=` value.
2023-05-19 16:20:54 +01:00
Chipster f71ce0ecf5
Merge branch 'g4klx:master' into master 2023-05-19 10:00:52 -05:00
Chipster 1e53f55abb Update sample INI with quoted `Symbol=` value. 2023-05-19 10:00:04 -05:00
Jonathan Naylor 4ac963b1d0
Update NXDNHosts.txt 2023-05-09 14:25:17 +01:00
Jonathan Naylor 668b32add6
Merge pull request #300 from Kimberly-McBlaze/master
Update NXDNHosts.txt
2023-04-13 12:11:52 +01:00
Kimberly McBlaze 586d82df54
Update NXDNHosts.txt
Removed "56987 Mother Owl" because I no longer host that reflector
Changed the hostname of "21909 PRIDE" due to moving to new host
2023-04-12 15:44:23 -07:00
Kimberly McBlaze 73583c5765
Update NXDNHosts.txt 2023-04-12 15:39:21 -07:00
Jonathan Naylor 4c37482329
Merge pull request #299 from pu4ron/patch-2 2023-04-09 10:16:30 +01:00
pu4ron ac0b340808
Update NXDNHosts.txt
Hello! Please modify reflector nxdn 7245 address to:

pu4ron.dynv6.net

Grateful!
2023-04-08 21:41:07 -03:00
Jonathan Naylor ca1428a6ce
Update NXDNHosts.txt 2023-04-02 19:47:57 +01:00
Jonathan Naylor e4ebc6ea23
Merge pull request #297 from m0glj/patch-26 2023-04-02 17:18:24 +01:00
M0GLJ 8b56973f32
Update NXDNHosts.txt 2023-04-02 17:17:32 +01:00
Jonathan Naylor 80eeac53c1
Merge pull request #296 from m0glj/patch-25 2023-04-02 17:08:27 +01:00
M0GLJ 224acb9bfd Update NXDNHosts.txt 2023-04-02 16:39:59 +01:00
Jonathan Naylor 0555e16a4c
Merge pull request #294 from pu4ron/patch-1 2023-03-21 18:41:39 +00:00
pu4ron 0423d53bf2
Update NXDNHosts.txt 2023-03-21 15:22:50 -03:00
Jonathan Naylor 37a01bc52c
Merge pull request #293 from m0glj/patch-22 2023-03-19 17:01:29 +00:00
M0GLJ c28169bd48
Update NXDNHosts.txt
New Reflector
2023-03-19 16:50:17 +00:00
Jonathan Naylor 32144123b1 Update NXDNHosts.txt 2023-03-13 21:18:20 +00:00
Jonathan Naylor e9371e6510
Merge pull request #292 from m0glj/patch-21 2023-03-04 19:02:09 +00:00
Jonathan Naylor 7ea328a4f2
Merge pull request #291 from m0glj/patch-20 2023-03-04 19:01:28 +00:00
M0GLJ 1b31929069
Update NXDNHosts.txt
New Reflector
2023-03-03 19:21:16 +00:00
M0GLJ 7a8e4eef9b
Update NXDNHosts.txt 2023-03-03 18:46:11 +00:00
Jonathan Naylor f804894b88
Merge pull request #290 from Merlinv3/patch-21 2023-03-03 13:12:03 +00:00
Merlinv3 c322d555da
Update NXDNHosts.txt
Update NXDNHosts.txt
2023-03-03 13:37:24 +01:00
Jonathan Naylor 486106a9c7 Remove the NXDN Reflector. 2023-02-23 19:34:37 +00:00
Jonathan Naylor 3bc2a1415b
Merge pull request #289 from ShaYmez/patch-2 2023-02-22 08:02:24 +00:00
M0VUB 25399fbf90
Update NXDNHosts.txt
Add 2350 & 23416
2023-02-21 22:55:47 +00:00
Jonathan Naylor a7fe16eedd
Merge pull request #288 from n2wns/master 2023-02-18 14:19:02 +00:00
N2WNS c32a8ca641
Update NXDNHosts.txt 2023-02-18 08:32:23 -05:00
Jonathan Naylor 1a9244ff44
Merge pull request #287 from W0CHP/master 2023-02-17 18:03:32 +00:00
Chipster 1474e16bb1 Add mode type to APRS string. Make APRS band/offset string a bit more consistent. 2023-02-17 06:22:58 -06:00
Jonathan Naylor 0e04fb82bd
Merge pull request #285 from Merlinv3/patch-19 2023-02-15 20:57:16 +00:00
Jonathan Naylor 6d167eef2d
Merge pull request #286 from Merlinv3/patch-20 2023-02-15 18:22:21 +00:00
Merlinv3 bc51b70195
Update NXDNHosts.txt
Update NXDNHosts.txt New Reflector
2023-02-14 22:18:11 +01:00
Merlinv3 3241ccad96
Update NXDNHosts.txt
NXDNHosts.txt Update ADD New Reflector
2023-02-14 15:43:43 +01:00
Jonathan Naylor d0c0ce16f5 Update to gpsd 3.2.1 API. 2023-02-13 17:54:56 +00:00
Jonathan Naylor 2a455a83e1
Merge pull request #284 from W0CHP/master 2023-02-13 15:56:47 +00:00
Chipster e215ad6a1b
Merge branch 'g4klx:master' into master 2023-02-13 09:32:49 -06:00
Chipster a99083c25c For NXDNGw, add missing symbol func. in offset/no-offset cconditions 2023-02-13 09:32:01 -06:00
Jonathan Naylor c9915170a0
Merge pull request #283 from W0CHP/master 2023-02-13 15:09:17 +00:00
Chipster 9f09acbd96 Add APRS Symbol option (based on my PR g4klx/DMRGateway#122) 2023-02-13 08:19:42 -06:00
Jonathan Naylor 4b6e3afed2
Merge pull request #282 from FredB1959/patch-3 2023-02-13 13:33:30 +00:00
FredB1959 4cf46733a0
Update NXDNHosts.txt
Changed @ in #
2023-02-13 08:11:18 +01:00
Jonathan Naylor 7eddd04566
Merge pull request #281 from FredB1959/patch-3 2023-02-12 15:49:45 +00:00
FredB1959 00e9ea8c9c
Update NXDNHosts.txt
Added new reflector 20426
2023-02-11 07:50:52 +01:00
Jonathan Naylor 1b7017acdc
Merge pull request #279 from Merlinv3/patch-18 2023-02-07 16:26:08 +00:00
Merlinv3 15123e1c25
Update NXDNHosts.txt
hello ! I made some changes :
I added correct dns.
I have deleted duplicates
thank you very much as always !
2023-02-07 16:52:35 +01:00
Jonathan Naylor 291a5f9e12 Update NXDNHosts.txt 2023-02-03 14:36:30 +00:00
Jonathan Naylor 151e82f9b8
Merge pull request #277 from N6DOZ/patch-4 2023-01-31 15:29:35 +00:00
Rudy aee966eb9c
Change to 31264 Reflector Information
As per request from the owner / operator / trustee of Backyard Repeater Owners Of America (XLX625 The BROniverse WA8BRO www.wa8bro.com), Del WW2MI - as the group is not affiliated with the 31264 NXDN reflector. Please contact Del WW2MI at del@beauchamp.info with regards to this matter.
2023-01-31 07:26:53 -08:00
Jonathan Naylor e09f6ae4f8
Merge pull request #276 from N6DOZ/patch-3
Update NXDNHosts.txt - Added 51547 Reflector
2023-01-29 15:48:33 +00:00
Rudy c6b366d05d
Update NXDNHosts.txt
# 51547 KAPIHAN Network
51547	nxdn.kapihan.net	41400
2023-01-29 07:14:17 -08:00
Jonathan Naylor 788c31c661
Merge pull request #275 from Merlinv3/patch-17 2023-01-28 15:25:54 +00:00
Merlinv3 85cfa1631e
UPDATE NXDNHosts.txt
sorry now is ok
2023-01-28 16:22:53 +01:00
Merlinv3 ff3084ff3c
Update NXDNHosts.txt
Update NXDNHosts.txt for new NL NXDN reflector
2023-01-28 16:08:11 +01:00
Jonathan Naylor 4f4637d854
Merge pull request #274 from RobertMTalbot/patch-1 2023-01-28 09:49:07 +00:00
BudT 1c0fbaf50e
Update NXDNHosts.txt
Delete deprecated TGs 31088 and 31092
2023-01-27 18:11:13 -07:00
Jonathan Naylor e415982ed1
Merge pull request #272 from DU8BL/master 2023-01-27 07:31:12 +00:00
Bj Lee 1c3246e10a
Update NXDNHosts.txt 2023-01-27 15:10:42 +08:00
Jonathan Naylor 2486103fb8
Merge pull request #271 from W2GLD/patch-3 2023-01-22 14:18:36 +00:00
W2GLD f3f056f6c0
Update NXDNHosts.txt
Modified line# 387/388 with new web host domain and description update.
2023-01-21 14:29:45 -05:00
Jonathan Naylor adf15fdc9f
Merge pull request #270 from Hubok/patch-4 2023-01-17 08:10:29 +00:00
Jonathan Naylor d623451f71
Merge pull request #269 from n2wns/master 2023-01-17 08:09:20 +00:00
Hubok eeeae8dcc7
Update NXDNHosts.txt
Retiring old reflectors, renumbering 5621 -> 926
2023-01-17 01:43:41 -05:00
N2WNS a4964b0e11
Merge pull request #2 from n2wns/Update-3400
Update NXDNHosts.txt
2023-01-16 21:10:29 -05:00
N2WNS 430c60f496
Update NXDNHosts.txt 2023-01-16 21:09:46 -05:00
Jonathan Naylor 67f91534a2
Update NXDNHosts.txt 2023-01-15 15:44:53 +00:00
Jonathan Naylor fa6e26b7be
Merge pull request #268 from Kool475/patch-1 2023-01-08 13:13:27 +00:00
Kool475 df91158137
Update NXDNHosts.txt 2023-01-07 23:27:54 -05:00
Jonathan Naylor 0c163b3437 Update NXDNHosts.txt 2022-11-16 19:30:58 +00:00
Jonathan Naylor ddc9df34a5
Merge pull request #265 from F1PTL/patch-2
Update NXDNHosts.txt
2022-11-16 19:28:13 +00:00
Bruno 2597317152
Update NXDNHosts.txt
Update Server NXDN France
# 65208 French-NXDN
65208	nxdn.f5dan.fr  41400
2022-11-15 19:10:19 +01:00
Jonathan Naylor 1d2fa6a6dd
Merge pull request #262 from M0UPM/patch-1 2022-10-27 15:17:39 +01:00
M0UPM 587852f727
Update NXDNHosts.txt 2022-10-27 14:45:51 +01:00
Jonathan Naylor 581a134076
Merge pull request #260 from yuvelq/patch-1 2022-10-20 14:01:48 +01:00
Christian OA4DOA 393032e35e
Update NXDNHosts.txt
Our domain has been changed to dmr-peru.net could you update it in the repository please?
2022-10-20 06:56:20 -05:00
Jonathan Naylor 522448917e
Merge pull request #259 from pa3esz/patch-3 2022-10-16 14:51:17 +01:00
Jonathan Naylor 5b130de88f
Merge pull request #258 from maq1017/patch-2 2022-10-16 14:50:34 +01:00
pa3esz 2821ee4aee
Update NXDNHosts.txt 2022-10-15 18:21:21 +02:00
maq1017 d7c8557448
Update NXDNHosts.txt 2022-10-15 15:45:15 +01:00
Jonathan Naylor 7c1ab8ce7a
Merge pull request #257 from maq1017/patch-1
Update NXDNHosts.txt
2022-10-14 22:22:07 +01:00
maq1017 45eb6ccde4
Update NXDNHosts.txt
Added reflector 841 - Team Wave
2022-10-14 13:19:24 +01:00
Jonathan Naylor b1e63d84e5
Update NXDNHosts.txt 2022-10-11 16:55:58 +01:00
Jonathan Naylor b555fa101e
Merge pull request #256 from m0glj/patch-19
Update NXDNHosts.txt
2022-10-10 19:12:03 +01:00
M0GLJ 33706547dd
Update NXDNHosts.txt 2022-10-09 00:12:15 +01:00
M0GLJ 31941d9ba1
Update NXDNHosts.txt
Change Host Name
2022-10-09 00:07:05 +01:00
Jonathan Naylor 50abe6f672
Merge pull request #255 from pa3frh/patch-1
Update NXDNHosts.txt
2022-10-04 18:37:16 +01:00
pa3frh 5e03f005e4
Update NXDNHosts.txt 2022-10-04 19:32:23 +02:00
Jonathan Naylor a18191b360
Update NXDNHosts.txt 2022-10-02 18:39:25 +01:00
Jonathan Naylor ff0e1e7317
Merge pull request #252 from skynetgwds/master
Update NXDNHosts.txt
2022-09-18 15:17:35 +01:00
Gareth GM0WUR 1ff8a141ca
Update NXDNHosts.txt 2022-09-17 16:03:33 +01:00
Jonathan Naylor a2c73f7a3c
Update NXDNHosts.txt 2022-09-15 19:05:28 +01:00
Jonathan Naylor c830390836
Merge pull request #249 from MW0MWZ/patch-1 2022-09-09 17:25:41 +01:00
MW0MWZ cc9609d4e2
Update NXDNHosts.txt
Update ICQ Podcast Host
2022-09-09 17:24:44 +01:00
Jonathan Naylor b559cf5eab
Merge pull request #248 from Merlinv3/patch-16 2022-09-07 17:51:24 +01:00
Merlinv3 208ff94c5a
Update NXDNHosts.txt
Update NXDNHosts.txt thank you very much for all the work these days
2022-09-07 15:59:58 +02:00
Jonathan Naylor 434c71d665
Merge pull request #247 from Merlinv3/patch-15
Update NXDNHosts.txt
2022-09-06 08:15:21 +01:00
Merlinv3 4f7ba10b45
Update NXDNHosts.txt
Update NXDNHosts.txt all the districts of Spain
2022-09-06 09:10:45 +02:00
Jonathan Naylor 38e6db94ad
Merge pull request #246 from Merlinv3/patch-14
Update NXDNHosts.txt
2022-09-05 21:32:39 +01:00
Merlinv3 66fd14697e
Update NXDNHosts.txt
sorry now is in numerical order .... thanks for letting me know! 73:)
2022-09-05 22:27:28 +02:00
Jonathan Naylor 01e04579f7
Merge pull request #244 from hp3icc/patch-1 2022-09-05 06:04:41 +01:00
Esteban Mackay Q f4f2cdb6ab
Update NXDNHosts.txt 2022-09-04 22:16:39 -05:00
Jonathan Naylor 77b930bf12
Merge pull request #243 from Merlinv3/patch-12 2022-09-04 13:25:21 +01:00
Merlinv3 7868c805f2
Update NXDNHost.txt
Add New TREEHOUSE NXDN BY PA7LIM
http://nxdn.pa7lim.nl/
2022-09-04 08:47:34 +02:00
Jonathan Naylor ad94417ef6
Merge pull request #242 from Merlinv3/patch-11 2022-09-03 18:53:16 +01:00
Merlinv3 b91cfade36
Update NXDNHosts.txt
update NXDNHosts.txt now they will use dns so as not to have to make changes in the future
2022-09-03 14:54:25 +02:00
Jonathan Naylor df43986b50
Merge pull request #240 from Merlinv3/patch-10 2022-09-01 08:38:03 +01:00
Merlinv3 7983a4c9b4
UPDATE NXDNHosts.txt
UPDATE NXDNHosts.txt thx
2022-08-31 18:43:05 +02:00
Jonathan Naylor 883e1006a7
Merge pull request #239 from Guanchindeverin/patch-1
Update NXDNHosts.txt
2022-08-30 21:26:45 +01:00
Guanchindeverin ff57626365
Update NXDNHosts.txt 2022-08-30 20:10:38 +01:00
Guanchindeverin ce6da5c7b5
Update NXDNHosts.txt 2022-08-30 20:05:28 +01:00
Guanchindeverin 365fae1b9d
Update NXDNHosts.txt 2022-08-29 16:40:19 +01:00
Jonathan Naylor b24e860c6c
Merge pull request #238 from Merlinv3/patch-9 2022-08-23 17:45:51 +01:00
Merlinv3 d510fe5ab4
Update NXDNHost.txt
NXDNHosts.txt update
2022-08-23 18:44:39 +02:00
Jonathan Naylor 52d151a9fd
Update NXDNHosts.txt 2022-08-14 16:50:50 +01:00
Jonathan Naylor a32ff79282
Merge pull request #237 from Merlinv3/patch-8
Update NXDNHosts.txt
2022-08-09 19:02:07 +01:00
Merlinv3 420a68811e
Update NXDNHosts.txt
Update NXDNHosts.txt for new
2022-08-09 19:18:59 +02:00
Jonathan Naylor 02e693c00c
Merge pull request #236 from W2GLD/patch-2 2022-08-07 08:22:27 +01:00
W2GLD b367a5d22a
Update NXDNHosts.txt
Made change to description at line# 315 for better clarity to users.
2022-08-06 11:21:49 -04:00
Jonathan Naylor 44da73826b
Merge pull request #235 from jriner63/patch-2 2022-07-22 12:44:41 +01:00
jriner63 377a477019
Update NXDNHosts.txt 2022-07-21 15:22:48 -04:00
Jonathan Naylor 206f9693f9 Add TG44155 2022-07-19 19:11:42 +01:00
Jonathan Naylor 3f0141ecf2
Merge pull request #233 from bh1nyr/master 2022-07-19 08:13:48 +01:00
bh1nyr 38e8129fe4
Update NXDNHosts.txt 2022-07-18 20:12:46 +08:00
bh1nyr 0abd218697
Merge pull request #2 from g4klx/master
update local
2022-07-18 20:11:34 +08:00
Jonathan Naylor 923570b6d3
Merge pull request #232 from Hubok/patch-3 2022-07-18 08:09:12 +01:00
Hubok 1e3e43b30b
Update NXDNHosts.txt 2022-07-18 01:03:03 -04:00
Jonathan Naylor cccfaa9d9b
Merge pull request #231 from ku-mi/master 2022-07-17 18:25:55 +01:00
ku-mi 3179316e66 Moving TG 26000 Poland to a different server 2022-07-17 15:57:54 +02:00
Jonathan Naylor 19de95e3bf
Merge pull request #230 from bh1nyr/master
Update NXDNHosts.txt
2022-07-17 12:19:59 +01:00
bh1nyr 0fee8b76ee
Update NXDNHosts.txt 2022-07-16 02:09:01 +08:00
bh1nyr 6f5903e63d
Update NXDN Hosts.txt
Build and Update NXDN Reflectors.
2022-07-16 02:06:21 +08:00
bh1nyr 4963c24471
Merge pull request #1 from g4klx/master
update local
2022-07-11 02:14:43 +08:00
Jonathan Naylor 7ecdc46b3e
Merge pull request #229 from bh1nyr/master
Update NXDNHost.txt
2022-07-10 15:33:30 +01:00
bh1nyr 324c2d5a4d
Update NXDNHost.txt
Add new nxdn Host bridge to BM TG46001 and change description for nxdn bridge TG46010.
Thanks!
2022-07-10 17:23:45 +08:00
Jonathan Naylor 95f76bdb15
Update NXDNHosts.txt 2022-07-04 16:29:02 +01:00
Jonathan Naylor fcdfc09404
Merge pull request #228 from wb6dtb/patch-5
Update NXDNHosts.txt
2022-07-04 16:27:44 +01:00
wb6dtb f28214a070
Update NXDNHosts.txt
Add TAC reflector to North America NXDN Reflector.
2022-07-03 12:43:49 -07:00
Jonathan Naylor 00bba1d8b8
Merge pull request #227 from bh1nyr/master 2022-07-01 10:29:24 +01:00
bh1nyr 3dfa9af218
Update NXDNHosts.txt
DNS resolve recovered. thx. 73 de BH1NYR
2022-07-01 16:51:17 +08:00
Jonathan Naylor 6fc5c39297 Add TG44000 2022-06-27 18:06:10 +01:00
Jonathan Naylor c2ff02da90 Update TG46010 2022-06-21 22:24:23 +01:00
Jonathan Naylor 67e0ffe4fe Add TG44160 2022-06-21 07:40:07 +01:00
Jonathan Naylor e9e40bd003
Merge pull request #223 from Hubok/patch-1
Update NXDNHosts.txt
2022-06-20 20:41:57 +01:00
Hubok a750b37313
Update NXDNHosts.txt 2022-06-20 07:38:56 -04:00
Jonathan Naylor b765c326f5 Added TG46010 2022-06-17 16:29:36 +01:00
Jonathan Naylor 24b55d5283
Merge pull request #220 from Kimberly-McBlaze/master
Update NXDNHosts.txt
2022-06-12 13:16:42 +01:00
Kimberly McBlaze 066b8b399c
Update NXDNHosts.txt 2022-06-10 22:58:55 -07:00
Jonathan Naylor 167f11c4b2
Merge pull request #219 from W2GLD/patch-1
Update NXDNHosts.txt
2022-05-23 19:02:33 +01:00
W2GLD def7427102
Update NXDNHosts.txt
Added lines 306-308, new NXDN reflector information.
2022-05-23 07:07:09 -04:00
Jonathan Naylor e742038b8b Update NXDNHosts.txt 2022-04-25 21:52:14 +01:00
Jonathan Naylor 01cb6fc3bb Update NXDNHosts.txt 2022-04-21 07:11:40 +01:00
Jonathan Naylor 2fb0e606ab
Merge pull request #217 from KP4CA/patch-2 2022-04-14 13:57:36 +01:00
Carlos (KP4CA) 75d19607a9
Update NXDNHosts.txt 2022-04-14 08:51:09 -04:00
Jonathan Naylor a5985b1176
Merge pull request #216 from Kimberly-McBlaze/patch-1
Update NXDNHosts.txt
2022-04-11 19:31:46 +01:00
Jonathan Naylor 5dddeefae8
Merge pull request #215 from vk3jed/patch-1
Update NXDNHosts.txt
2022-04-11 19:31:27 +01:00
Jonathan Naylor 9c4df30e58
Merge pull request #214 from 9V1LH/patch-2
Update NXDNHosts.txt
2022-04-11 19:31:09 +01:00
Kimberly McBlaze c111b3c317
Update NXDNHosts.txt
Added my reflector to the list on lines 180 - 181.
DE KJ7OMO
2022-04-09 02:09:16 -07:00
Tony Langdon 7fbaeccb44
Update NXDNHosts.txt
Add reflector for NXDN TG 50535.
2022-04-09 13:49:08 +10:00
Stephan bee0b78279
Update NXDNHosts.txt
Updated 20421
2022-03-31 17:11:19 +08:00
Jonathan Naylor 6668b3ef87
Merge pull request #213 from KP4CA/patch-1
Update NXDNHosts.txt
2022-03-29 20:51:38 +01:00
Carlos (KP4CA) 9602ae5d42
Update NXDNHosts.txt 2022-03-25 18:09:52 -04:00
Jonathan Naylor eca0339b35 Update TG20330s IP address 2022-03-16 19:05:03 +00:00
Jonathan Naylor 4ef2dc052b Update NXDNHosts.txt 2022-03-15 21:08:57 +00:00
Jonathan Naylor 64538ec811
Merge pull request #212 from firealarmss/patch-1
Update NXDNHosts.txt
2022-03-15 21:05:15 +00:00
Jonathan Naylor e22ff6fe37
Merge pull request #210 from nessenj/patch-1
Add 3160 to NXDNHosts.txt
2022-03-15 21:05:05 +00:00
firealarmss 10ea9b704c
Update NXDNHosts.txt
Adding KO4UYJ 31582
2022-03-13 23:12:11 -05:00
Jim Nessen 312dda3e6b
Add 3160 to NXDNHosts.txt 2022-03-06 14:35:41 -08:00
Jonathan Naylor 1124e4a1bb
Merge pull request #209 from yl3im/master
Update hosts with 37500 and 63600. Update user list from RadioID.
2022-03-06 20:17:18 +00:00
Jonathan Naylor 9e3256e8bd Update NXDNHosts.txt 2022-03-06 20:16:43 +00:00
Jonathan Naylor 88bff78a73
Merge pull request #208 from g0anv/patch-1
Please add TG23491 NXDN Cambridge to the NXDNHosts.txt file Many than…
2022-03-06 20:14:34 +00:00
Inga Muste a8f3b335f2 Update hosts with 37500 and 63600. 2022-02-25 14:13:43 +02:00
Inga Muste 44c777a2d1 Update user list from RadioID. 2022-02-25 14:10:32 +02:00
g0anv dd1f81f612
Please add TG23491 NXDN Cambridge to the NXDNHosts.txt file Many thanks Daryl, G0ANV 2022-02-11 20:12:48 +00:00
Jonathan Naylor f9f1530dc9
Merge pull request #206 from f1rmb/connection_status_to_static_at_startup 2022-01-25 22:49:48 +00:00
Daniel Caujolle-Bert 4f3bc66544 Change negation checking coding style. 2022-01-25 18:46:33 +00:00
Daniel Caujolle-Bert a69af8ad79 Fix Static on startup.
If a static talkgroup is set in the configuration file is set, some 3 poll frames are sent, but replies are ignored, hence the connection status stays disconnected, and localnetwork won't get any data also.
2022-01-25 03:45:49 +00:00
Jonathan Naylor f907b4ce3c
Merge pull request #205 from f1rmb/network_status
Add new remote command:
2022-01-24 07:11:21 +00:00
Daniel Caujolle-Bert 3afa96c6cd Add new remote command:
- status: displays network connection status (n/a, conn, disc), just like DMRGateway/MMDVMHost.
 - host: display connected host, or NONE if disconnected (surrounded with double quotes).
2022-01-23 17:44:44 +00:00
57 changed files with 602 additions and 6927 deletions

3
.gitignore vendored
View File

@ -15,5 +15,6 @@ x64
.vs
NXDNGateway/NXDNGateway
NXDNParrot/NXDNParrot
NXDNReflector/NXDNReflector
NXDNGateway/GitVersion.h
NXDNParrot/GitVersion.h

View File

@ -1,4 +1,4 @@
SUBDIRS = NXDNGateway NXDNParrot NXDNReflector
SUBDIRS = NXDNGateway NXDNParrot
CLEANDIRS = $(SUBDIRS:%=clean-%)
INSTALLDIRS = $(SUBDIRS:%=install-%)

View File

@ -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}") = "NXDNParrot", "NXDNParrot\NXDNParrot.vcxproj", "{2AE94EAA-FD57-45C9-8555-6425CFA777A3}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NXDNGateway", "NXDNGateway\NXDNGateway.vcxproj", "{8B7A5406-8560-4B40-ADDA-9B8EBF93E232}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NXDNReflector", "NXDNReflector\NXDNReflector.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

View File

@ -34,6 +34,7 @@ m_latitude(0.0F),
m_longitude(0.0F),
m_height(0),
m_desc(),
m_symbol(),
m_aprsAddr(),
m_aprsAddrLen(0U),
m_aprsSocket()
@ -61,11 +62,12 @@ CAPRSWriter::~CAPRSWriter()
{
}
void CAPRSWriter::setInfo(unsigned int txFrequency, unsigned int rxFrequency, const std::string& desc)
void CAPRSWriter::setInfo(unsigned int txFrequency, unsigned int rxFrequency, const std::string& desc, const std::string& symbol)
{
m_txFrequency = txFrequency;
m_rxFrequency = rxFrequency;
m_desc = desc;
m_symbol = symbol;
}
void CAPRSWriter::setStaticLocation(float latitude, float longitude, int height)
@ -173,19 +175,19 @@ void CAPRSWriter::sendIdFrameFixed()
char desc[200U];
if (m_txFrequency != 0U) {
float offset = float(int(m_rxFrequency) - int(m_txFrequency)) / 1000000.0F;
::sprintf(desc, "MMDVM Voice %.5LfMHz %c%.4lfMHz%s%s",
::sprintf(desc, "MMDVM Voice (NXDN) %.5LfMHz %c%.4lfMHz%s%s",
(long double)(m_txFrequency) / 1000000.0F,
offset < 0.0F ? '-' : '+',
::fabs(offset), m_desc.empty() ? "" : ", ", m_desc.c_str());
} else {
::sprintf(desc, "MMDVM Voice%s%s", m_desc.empty() ? "" : ", ", m_desc.c_str());
::sprintf(desc, "MMDVM Voice (NXDN)%s%s", m_desc.empty() ? "" : ", ", m_desc.c_str());
}
const char* band = "4m";
if (m_txFrequency >= 1200000000U)
band = "1.2";
band = "23cm/1.2GHz";
else if (m_txFrequency >= 420000000U)
band = "440";
band = "70cm";
else if (m_txFrequency >= 144000000U)
band = "2m";
else if (m_txFrequency >= 50000000U)
@ -209,17 +211,21 @@ void CAPRSWriter::sendIdFrameFixed()
::sprintf(lon, "%08.2lf", longitude);
std::string server = m_callsign;
std::string symbol = m_symbol;
size_t pos = server.find_first_of('-');
if (pos == std::string::npos)
server.append("-S");
else
server.append("S");
if (symbol.empty())
symbol.append("D&");
char output[500U];
::sprintf(output, "%s>APDG04,TCPIP*,qAC,%s:!%s%cD%s%c&/A=%06.0f%s %s\r\n",
::sprintf(output, "%s>APDG04,TCPIP*,qAC,%s:!%s%c%c%s%c%c/A=%06.0f%s %s\r\n",
m_callsign.c_str(), server.c_str(),
lat, (m_latitude < 0.0F) ? 'S' : 'N',
lon, (m_longitude < 0.0F) ? 'W' : 'E',
lat, (m_latitude < 0.0F) ? 'S' : 'N', symbol[0],
lon, (m_longitude < 0.0F) ? 'W' : 'E', symbol[1],
float(m_height) * 3.28F, band, desc);
if (m_debug)
@ -242,7 +248,11 @@ void CAPRSWriter::sendIdFrameMobile()
return;
#endif
#if GPSD_API_MAJOR_VERSION >= 10
if (m_gpsdData.fix.status != STATUS_FIX)
#else
if (m_gpsdData.status != STATUS_FIX)
#endif
return;
bool latlonSet = (m_gpsdData.set & LATLON_SET) == LATLON_SET;
@ -266,19 +276,19 @@ void CAPRSWriter::sendIdFrameMobile()
char desc[200U];
if (m_txFrequency != 0U) {
float offset = float(int(m_rxFrequency) - int(m_txFrequency)) / 1000000.0F;
::sprintf(desc, "MMDVM Voice %.5LfMHz %c%.4lfMHz%s%s",
::sprintf(desc, "MMDVM Voice (NXDN) %.5LfMHz %c%.4lfMHz%s%s",
(long double)(m_txFrequency) / 1000000.0F,
offset < 0.0F ? '-' : '+',
::fabs(offset), m_desc.empty() ? "" : ", ", m_desc.c_str());
} else {
::sprintf(desc, "MMDVM Voice%s%s", m_desc.empty() ? "" : ", ", m_desc.c_str());
::sprintf(desc, "MMDVM Voice (NXDN)%s%s", m_desc.empty() ? "" : ", ", m_desc.c_str());
}
const char* band = "4m";
if (m_txFrequency >= 1200000000U)
band = "1.2";
band = "23cm/1.2GHz";
else if (m_txFrequency >= 420000000U)
band = "440";
band = "70cm";
else if (m_txFrequency >= 144000000U)
band = "2m";
else if (m_txFrequency >= 50000000U)
@ -302,17 +312,21 @@ void CAPRSWriter::sendIdFrameMobile()
::sprintf(lon, "%08.2lf", longitude);
std::string server = m_callsign;
std::string symbol = m_symbol;
size_t pos = server.find_first_of('-');
if (pos == std::string::npos)
server.append("-S");
else
server.append("S");
if (symbol.empty())
symbol.append("D&");
char output[500U];
::sprintf(output, "%s>APDG03,TCPIP*,qAC,%s:!%s%cD%s%c&",
::sprintf(output, "%s>APDG03,TCPIP*,qAC,%s:!%s%c%c%s%c%c",
m_callsign.c_str(), server.c_str(),
lat, (rawLatitude < 0.0F) ? 'S' : 'N',
lon, (rawLongitude < 0.0F) ? 'W' : 'E');
lat, (rawLatitude < 0.0F) ? 'S' : 'N', symbol[0],
lon, (rawLongitude < 0.0F) ? 'W' : 'E',symbol[0]);
if (bearingSet && velocitySet)
::sprintf(output + ::strlen(output), "%03.0f/%03.0f", rawBearing, rawVelocity * 0.539957F);

View File

@ -47,7 +47,7 @@ public:
bool open();
void setInfo(unsigned int txFrequency, unsigned int rxFrequency, const std::string& desc);
void setInfo(unsigned int txFrequency, unsigned int rxFrequency, const std::string& desc, const std::string& symbol);
void setStaticLocation(float latitude, float longitude, int height);
@ -69,6 +69,7 @@ private:
float m_longitude;
int m_height;
std::string m_desc;
std::string m_symbol;
sockaddr_storage m_aprsAddr;
unsigned int m_aprsAddrLen;
CUDPSocket m_aprsSocket;

View File

@ -72,6 +72,7 @@ m_aprsAddress("127.0.0.1"),
m_aprsPort(8673U),
m_aprsSuffix(),
m_aprsDescription(),
m_aprsSymbol(),
m_networkPort(0U),
m_networkHosts1(),
m_networkHosts2(),
@ -235,6 +236,8 @@ bool CConf::read()
m_aprsSuffix = value;
else if (::strcmp(key, "Description") == 0)
m_aprsDescription = value;
else if (::strcmp(key, "Symbol") == 0)
m_aprsSymbol = value;
} else if (section == SECTION_NETWORK) {
if (::strcmp(key, "Port") == 0)
m_networkPort = (unsigned short)::atoi(value);
@ -415,6 +418,11 @@ std::string CConf::getAPRSDescription() const
return m_aprsDescription;
}
std::string CConf::getAPRSSymbol() const
{
return m_aprsSymbol;
}
unsigned int CConf::getLogDisplayLevel() const
{
return m_logDisplayLevel;

View File

@ -65,6 +65,7 @@ public:
unsigned short getAPRSPort() const;
std::string getAPRSSuffix() const;
std::string getAPRSDescription() const;
std::string getAPRSSymbol() const;
// The Log section
unsigned int getLogDisplayLevel() const;
@ -134,6 +135,7 @@ private:
unsigned short m_aprsPort;
std::string m_aprsSuffix;
std::string m_aprsDescription;
std::string m_aprsSymbol;
unsigned short m_networkPort;
std::string m_networkHosts1;

View File

@ -102,8 +102,8 @@ unsigned int CIcomNetwork::read(unsigned char* data)
if (length <= 0)
return 0U;
if (!CUDPSocket::match(m_addr, addr)) {
LogWarning("Icom Data received from an unknown address or port");
if (!CUDPSocket::match(m_addr, addr, IMT_ADDRESS_ONLY)) {
LogWarning("Icom Data received from an unknown address");
return 0U;
}

View File

@ -2,11 +2,11 @@ CC = cc
CXX = c++
# Use the following CFLAGS and LIBS if you don't want to use gpsd.
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
# Use the following CFLAGS and LIBS if you do want to use gpsd.
#CFLAGS = -g -O3 -Wall -DHAVE_LOG_H -DUDP_SOCKET_MAX=2 -DUSE_GPSD -std=c++0x -pthread
#CFLAGS = -g -O3 -Wall -DHAVE_LOG_H -DUSE_GPSD -std=c++0x -pthread
#LIBS = -lpthread -lgps
LDFLAGS = -g

View File

@ -38,6 +38,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>
@ -312,9 +313,11 @@ void CNXDNGateway::run()
hangTimer.start();
}
} else if (currentTG == 0U) {
// Don't pass reflector control data through to the MMDVM
if (::memcmp(buffer, "NXDND", 5U) == 0) {
// Find the static TG that this audio data belongs to
bool poll = false;
// We weren't really connected yet, but we got a reply from a poll, or some data
if ((::memcmp(buffer, "NXDND", 5U) == 0) || (poll = (::memcmp(buffer, "NXDNP", 5U) == 0))) {
// Find the static TG that this audio data/poll belongs to
for (std::vector<CStaticTG>::const_iterator it = staticTGs.cbegin(); it != staticTGs.cend(); ++it) {
if (CUDPSocket::match(addr, (*it).m_addr)) {
currentTG = (*it).m_tg;
@ -333,7 +336,7 @@ void CNXDNGateway::run()
bool grp = (buffer[9U] & 0x01U) == 0x01U;
if (grp && currentTG == dstTG)
if (grp && currentTG == dstTG && !poll)
localNetwork->write(buffer + 10U, len - 10U);
LogMessage("Switched to reflector %u due to network activity", currentTG);
@ -539,6 +542,21 @@ void CNXDNGateway::run()
voice->linkedTo(currentTG);
}
}
} else if (::memcmp(buffer + 0U, "status", 6U) == 0) {
std::string state = std::string("nxdn:") + ((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*)&currentAddr, currentAddrLen, buffer, sizeof(buffer), 0, 0, NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
ref = std::string(buffer);
}
}
std::string host = std::string("nxdn:\"") + ((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);
}
@ -637,8 +655,9 @@ void CNXDNGateway::createGPS()
unsigned int txFrequency = m_conf.getTxFrequency();
unsigned int rxFrequency = m_conf.getRxFrequency();
std::string desc = m_conf.getAPRSDescription();
std::string symbol = m_conf.getAPRSSymbol();
m_writer->setInfo(txFrequency, rxFrequency, desc);
m_writer->setInfo(txFrequency, rxFrequency, desc, symbol);
bool enabled = m_conf.getGPSDEnabled();
if (enabled) {

View File

@ -40,6 +40,7 @@ Address=127.0.0.1
Port=8673
Suffix=N
Description=APRS Description
# Symbol="/r"
[Id Lookup]
Name=NXDN.csv

View File

@ -3,45 +3,96 @@
# The format of this file is the number of the Talk Group followed by the host name or address and port
#
# 14 www.spanish BY radiomania.net
14 nxdn14.nxdn.es 41400
# 38 Thailand
38 nxdn38.kozow.com 41400
# 112 Emergencias EA
112 112.nxdn.es 41401
# 137 Thailand - USA XLX Bridge
137 nxdn137.mywire.org 41400
# 138 Thailand
138 nxdn138.freeddns.org 41400
138 nxdn138.freeddns.org 41400
# 148 Thailand Link TO XLX148 Module X
148 nxdn.hs3tdi.com 41400
# 149 Thailand
149 nxdn.pwk.ac.th 41400
# 202 HELLAS Zone
202 hellaszone.com 41400
202 hellaszone.com 41400
# 204 Netherlands
204 nxdn.repeaters-haaglanden.nl 41400
# 214 RED SPAIN
214 nxdn214.xreflector.es 41400
214 214nxdn.nxdn.es 41401
# 224 RED SPAIN
224 nxdn224.nxdn.es 41401
# 226 Romania YO NXDN Network
226 nxdn.dstar-yo.ro 41400
# 235 DVSPH UK Wide
235 nxdn.dvsph.net 41400
# 260 HBLink Poland
260 nxdn.hblink.pl 41400
260 nxdn.hblink.pl 41400
# 280 Cyprus-NXDN Cyprus
280 nxdn.greece.freedmr.online 41404
# 302 P25 Canada
302 p25canada.hopto.org 41400
# 401 CT-RI-NXDN
401 nxdn.mooo.com 41401
# 420 Super Freq
420 nxdn.superfreqdigital.com 41400
420 nxdn.superfreqdigital.com 41400
# 530 New Zealand
530 zldigitalreflectors.hopto.org 41400
530 zldigitalreflectors.hopto.org 41400
# 545 XLX545E PA
545 70.44.20.24 41401
545 70.44.20.24 41401
# 621 HRCC LINK
621 urf.hrcc.link 41400
# 707 RuralMN Reflector
707 707nxdn.kd0ioe.com 41400
# 711 NXDN NL
711 nxdn1.digitalevoice.nl 41400
# 712 NXDN JP
712 nxdn.xreflector-jp.org 41400
# 730 Chile NXDN Reflector to BM TG 730
730 sdradio.cl 41400
# 805 US RocketCity-AL-NXDN Bridge
805 45.32.166.46 41400
# 822 Thailand NXDN to BM TG 520822
822 nxdn.dstarthailand.com 41400
# 841 Team Wave NXDN Bridge
841 mx0wvv.ddns.net 41400
# 847 Chandler Hams
847 xlx847.kk7mnz.com 41400
# 848 Chandler Hams
848 xlx848.kk7mnz.com 41400
# 910 Washington DC - Virginia - Maryland
910 nxdn910.freeddns.org 41400
@ -49,25 +100,28 @@
911 nxdn.k2cop.com 41400
# 914 Latin America
914 80.211.94.145 41400
914 914.nxdn.es 41400
# 926 HamFurs/LoFAR MultiMode Bridge
926 urf.kf3rry.org 41400
# 1007 Harley-Hangout TGIF TG-1007 Bridge
1007 43773.kb5rir.com 41400
1007 43773.kb5rir.com 41400
# 1200 Florida
1200 florida.nxref.org 41400
# 2140 DMRplus BM Multi
2140 94.177.235.81 41400
# 2020 GR-GREECE-DV-NXDN
2020 nxdn.greece.freedmr.online 41400
# 2225 IT Tuscany
2225 80.211.99.134 41400
# 2029 GR-Crete-DV-NXDN
2029 nxdn.greece.freedmr.online 41402
# 2231 IT Multiprotocollo Sardegna
2231 nxdn.is0.org 41400
# 2140 Treehouse NXDN
2140 2140.nxdn.es 41402
# 2241 IT TUSCANY MULTIP
2241 nxdn.grupporadiofirenze.net 41400
# 2147 Andalucia Room
2147 2147.nxdn.es 41400
# 2249 IT SICILIA
2249 nxdn.digitalsicilia.it 41400
@ -78,6 +132,12 @@
# 2265 Baia Mare YO5 NXDN Network
2265 nxdn.dstar-yo.ro 41405
# 2345 CQ-North UK
2345 nxdn.cqnorth.org.uk 41400
# 2350 UK ChatterBOX
2350 nxdn2350.freestar.network 41401
# 2503 RU DMR
2503 nxdn.r1ik.ru 41400
@ -88,37 +148,73 @@
2724 dmr.nrsi.ie 41400
# 3023 Ontario Crosslink
3023 ontxlink.hopto.org 41400
3023 ontxlink.hopto.org 41400
# 3120 LKDVM NXDN
3120 lkdvm.nxdn.es 41400
# 3142 Pennsylvania
3142 3.215.215.169 41402
# 3160 K6JWN Crossroads
3160 nxdn.k6jwn.org 41400
# PRadise
3300 nxdn3300.from-pr.com 41400
# 3400 W2BTN Group
3400 w2btn.dmrnet.net 41400
# PT RICO LINK
3306 3306.nxdn.es 41400
# 3400 3400 Digital Group (NJ Multimode Reflector)
3400 3400.ddns.net 41400
# 5057 VK7 TAS
5057 45.248.50.37 41400
5057 45.248.50.37 41400
# 7144 Chiriqui Link Panama
7144 nxdn.pa7lim.nl 41400
# 7160 Peru Digital
7160 nxdn.dmr-peru.pe 41400
7160 nxdn.dmr-peru.net 41400
# 7221 FreeDMR Argentina
7221 nxdn.freedmr.ar 41400
# 7225 Multiprotocolo Argentina
7225 argnxdn.ddnsfree.com 41400
# 7240 MASTER-SUL Brasil
7240 nxdn.freedmr-brasil.qsl.br 41400
# 7245 Brasil Multiprotocolo
7245 pu4ron.dynv6.net 41400
# 7309 CHILE-LINK NXDN Reflector to BM TG 73099
7309 sdradio.cl 41401
# 7487 Uruguay Link
7487 uruguay.nxdn.es 41400
# 7941 White Mountain Repeater Association
7941 wmra-nxdn.mooo.com 41400
# 8465 Ecuador
8465 jjsc.ddns.net 41400
# 9480 ICQPODCAST - ICQ DIGITAL GROUP
9480 reflectors.icqpodcast.com 42400
9480 46.101.36.246 41400
# 9517 M17 Project - M17-M17 C Reflector bridge
9517 112.213.34.65 41401
# 9846 NXDN Portal to WW8GM YSF network www.gmarc.org
9846 nxdn.dudetronics.com 41401
# 10200 North America
10200 dvswitch.org 42400
10200 dvswitch.org 42400
# 10201 North America TAC
10201 10201.dyndns.org 41400
# 10301 HBLINK Espana
10301 ea5gvk.duckdns.org 41400
@ -135,51 +231,69 @@
# 10922 CQ-UK
10922 81.150.10.62 41400
# 17000 M17 Project
17000 107.191.48.144 41400
# 11069 KK6RQ NXDN Reflector
11069 area52.zapto.org 41400
# 17603 URFM17 Universal Reflector
17603 urf.m17.link 41400
# 20000 Europe, German speaking
20000 89.185.97.38 41400
# 20201 NXDN Athens GR HBLink
20201 stargate-dmr.net 41400
20201 stargate-dmr.net 41400
# 20211 GR-Lamia-DV-NXDN
20211 nxdn.greece.freedmr.online 41403
# 20281 GR-KERKYRA-DV-NXDN
20281 nxdn.greece.freedmr.online 41401
# 20222 NXDN HELLAS-FRN
20222 greece-frn.ddns.net 41400
# 20328 NXDN German Pegasus Project
20328 nxdn.projekt-pegasus.net 41400
# 20330 NXDN German DE-RAMSES Project
20330 161.97.140.131 41400
# 20333 NXDN LausitzLink Germany
20333 nxdn02.bzsax.de 41400
20330 81.169.173.132 41400
# 20421 DL-Nordwest (dl-nordwest.com) by 9V1LH/DG1BGS and DK5BS
20421 9v1lh.spdns.org 41400
20421 dl-nordwest.com 41400
# 20424 Rijmond regio Rotterdam
20424 nxdn.pa7lim.nl 41400
# 20426 Boreft regio Bodegraven
20426 pa8f.nl 41400
# 20945 Deutschland DL1BH
20945 dl1bh.ddns.net 41400
# 21410 NXDN SPAIN
21410 nxdn21410.nxdn.es 41400
# 21426 FreeSTAR SPAIN
21426 nxdn.pa7lim.nl 41400
# 2147 Andalucia Room
21401 2147.nxdn.es 41400
# 21418 NXDN RC Veleta
21418 rcveleta.xreflector.es 41400
# 21430 Alcayna
21430 alcayna.duckdns.org 41400
# 21430 EA5URM-Murcia
21430 ea5urm-murcia.duckdns.org 41400
# 21465 ADER Multimode
21465 aderdigital.ddns.net 41400
# 21468 Canarias NXDN
21468 nxdn.pa7lim.nl 41400
# 21909 PRIDE - LGBTQIA+ Hams
21909 ham.kimberlychase.com 41400
# 22200 IT HBLINK ITALY
22200 nxdn.hblink.it 41400
# 22202 IT SARDINIA
22202 87.106.152.249 41400
# 22209 IT Radio Chat NXDN
22209 it-radiochat.ddns.net 41400
# 22220 IT ItalyNet Conference
22220 198.245.55.177 41400
@ -189,38 +303,56 @@
# 22245 IT PIEDMONT GDO
22245 nxdngdo.duckdns.org 41400
# 22251 IT TG22251 TOSCANA
22251 nxdn5.grupporadiofirenze.net 41400
# 22252 IT MULTIPROTOCOL NETWORK
22252 46.226.178.80 41400
# 22258 D2ALP HBLink Italia
22258 94.177.173.53 41400
# 22292 IT MP XLX039/B BM2222
22292 hblink.dmrbrescia.it 41400
# 22292 Italy-MP TG 22292 BM
22292 nxdn.grupporadiofirenze.net 41400
# 22488 Italy Centro
22488 185.203.119.229 41400
# 22825 Swiss NXDN Reflerctor
22825 212.237.33.114 41400
# 23416 400Club
23416 nxdn23416.freestar.network 41402
# 23426 FreeSTAR UK
23426 nxdn.freestar.network 41400
23426 nxdn.freestar.network 41400
# 22488 Digital Network
22488 185.203.119.229 41400
# 23491 NXDN Cambridge
23491 nxdn-cambridge.dyndns.org 41400
# 23530 Yorkshire UK, https://dvswitch.uk/nxdn
23530 194.146.44.13 41400
# 23511 LEFARS Multi-Reflector
23511 xlxlef.gb7hh.co.uk 41400
# 23525 Extended Freedom Network M0XFN
23525 nxdn.m0xfn.radio 41401
# 23530 CQ-UK-North, http://109.228.47.204/nxdn
23530 109.228.47.204 41400
# 23551 NXDN Scotland
23551 nxdnscotland.ddns.net 41400
# 23556 DVSPH Multimode
23556 xlx600.dvsph.net 41400
# 23595 OZ-DMR_CHAT
23595 reflectors.oz-dmr.uk 41400
23595 nxdn.oz-dmr.network 41400
# 25000 NX Core
25000 173.166.94.77 41400
# 25577 UA Azimuth
25577 178.136.234.51 41400
25577 nxdn.ur4wwr.org 41400
# 25617 Russia Kavkaz
25617   kavkaz.qrz.ru 41400
@ -229,7 +361,7 @@
25641 194.182.85.217 41400
# 26000 Poland
26000 80.211.249.221 41400
26000 185.174.14.75 41400
# 26078 Poland HBLink Network
26078 nxdn.hblink.kutno.pl 41400
@ -241,7 +373,7 @@
26085 91.245.81.2 41400
# 26200 Deutschland
26200 135.125.204.81 41400
26200 dl.nxdn.eu 41400
# 26810 Portuguese speakers
26810 nxcore.brandmeister.pt 41400
@ -250,7 +382,7 @@
28299 arcnxdn.duckdns.org 41400
# 29999 AllStarLink Bridge
29999 64.154.38.103 41400
29999 64.154.38.103 41400
# 30639 NorCal-Bridge / Multimode-NXDN
30639 nfonorcalnxdn.dyndns.org 41400
@ -261,39 +393,48 @@
# 31031 XLX310 Multimode Reflector
31031 ref.xlx310.com 41400
# 31059 Vidalia Net NXDN
31059 vidalianet.cbridge.net 41400
# 31081 Colorado Fun Machine WE0FUN Bridge to C4FM, DMR, DStar, P25 and AllStarLink (Analog) http://www.we0fun.com
31081 nxdn.we0fun.com 41400
# 31088 Colorado HD
31088 54.191.50.212 41400
# 31092 Connecticut Chat
31092 nxdn.alecwasserman.com 41400
# 31121 First Coast FL
31121 dvse.dmrnet.net 41400
# 31137 Kingsland Digital Link
31137 74.91.119.94 41400
# 31138 Kingsland Local Ga
31138 kingsland.cbridge.net 41400
# 31171 Illinois Link
31171 illink.radiotechnology.xyz 41400
# 31177 WESDIG Western US Digital Group
31177 nxdn.wesdig.com 41400
# 31188 Southern Indiana
31188 w9windigital.org 41400
# 31226 WorldWide Dx System
31226 198.245.53.107 41400
31226 74.208.163.225 41400
# 31238 Foxhole Radio Bridged Network
31238 nxdn.foxhole.radio 41400
# 31257 NEARC
31257 nxdn.w0jay.com 41400
# 31264 XLX625 The BROniverse www.wa8bro.com
# 31264 Dudetronics NXDN
31264 nxdn.dudetronics.com 41400
# 31340 Central New Jersey
31340 cnjham.msmts.com 41400
# 31399 OhioLink Network crossmode. http://olnradio.digital
31399 xlx.kd8grn.net 41400
# 31403 Oklahoma Link
31403 3.208.70.29 41400
@ -306,9 +447,15 @@
# 31444 Rhode Island Digital Link
31444 18.219.32.21 41400
# 31490 utah bridge to dmr 314900
31490 utah00.utahdrn.org 41400
# 31581 KD2UQK Long Island, NY - NXDN Reflector
31581 kd2uqk.ham-radio-op.net 41400
# 31582 KO4UYJ Milton, Fl - NXDN Reflector
31582 ko4uyj.com 41400
# 31665 TGIF Network
31665 tgif.network 41400
@ -324,47 +471,105 @@
# 32103 CW-Ops Academy
32103 cwops.dyndns.org 41400
# 33015 KP4CA Digital Network
33015 kp4ca-nxdn.ddns.net 41400
# 33581 OMISS Group
33581 omiss.dyndns.org 41400
# 37030 SKYNET
37030 skynet.nxdn.es 41400
# 37224 Haiti NXDN
37224 44.98.254.130 41400
# 37500 Belarus Digital MultiMode Network
37500 xlx375.bfrr.by 41400
# 40721 Fusion Canada Fr /Wires-x /Ysf /Nxdn Network
40721 158.69.169.205 41400
# 45000 Korea
45000 nxdn.dvham.com 41400
# 46000 China
46000 120.234.41.144 41400
# 43389 SouthEast Link
43389 nxdn.lmarc.net 41400
# 44000 Japan
44000 nxdn44000.f5.si 41400
# 44120 Managed by JA2CCV
44120 nxdn.owari.biz 41400
# 44155 XLX298 YSF-NAGOYA BRIDGE NAGOYA JAPAN
44155 xrf298.mydns.jp 41400
# 45000 Korea
45000 nxdn.dvham.com 41400
# 45001 NXDN-DS5QDR Korea
45001 ds5qdr-mst.duckdns.org 41400
# 46000 China
46000 120.234.41.144 41400
# 46001 NXDN Link TG46001, China
46001 46001.bh1nyr.net 41400
# 46010 NXDN Link TG46010, Beijing, China
46010 46010.bh1nyr.net 41402
# 46516 NXDN Link TG46516, Xuzhou, China
46516 46516.bh1nyr.net 41404
# 50525 DMR TG50525 bridge
50525 50525.nxref.org 41400
# 50535 PrideNet multimode bridge
50535 p25tg50535.vkradio.com 41400
# 50599 BM NXCore bridge
50599 nxdn.duckdns.org 41490
# 51500 DX8WMG-NXDN
51500 dx8wmg-ysf.ddns.net 41400
# 51547 KAPIHAN Network
51547 nxdn.kapihan.net 41400
# 52000 Thailand DTDXA XLX520N
52000 nxdn.dtdxa.com 41400
# 52032 Surin Amateur Radio Association (HS3AS) ,Thailand,XLX149C
52032 hs3as.pwk.ac.th 41404
52032 hs3as.pwk.ac.th 41404
# 52149 XLX149 D Thailand
52149 nxdn149d.pwk.ac.th 41408
# 52910 XLX Nexus
52910 nxdn910x.mywire.org 41400
# 53099 New Zealand, 53099 linked to BM TG 53099
53099 203.86.206.49 41400
# 60777 Who Cares ARG (URF239 A) https://whocaresradio.com/reflector
60777 urf239.whocaresradio.com 41400
# 63600 Latvian Digital MultiMode Network
63600 xlx.ham.lv 41400
# 64003 ELITE Group
64003 51.77.213.200 41400
# 65000 World Wide
65000 176.9.1.168 41400
65000 176.9.1.168 41400
# 65100 NXDN - 2007DXGROUP
65100 89.46.75.115 41400
# 65208 French-Test
65208 m55.evxonline.net 41400
# 65206 XLX210 YSF-BELGIUM M17BEL Bridges http://freedmr.be/nxdn
65206 161.97.169.233 41400
# 65208 French-NXDN
65208 nxdn.f5dan.fr 41400
# 65209 VARG http://www.varg.club
65209 3.215.215.169 41410

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2014,2016,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2014,2016,2018,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 @@
CNXDNNetwork::CNXDNNetwork(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 CNXDNNetwork::open()
{
LogInfo("Opening NXDN 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 CNXDNNetwork::writeData(const unsigned char* data, unsigned int length, unsigned short srcId, unsigned short dstId, bool grp, const sockaddr_storage& addr, unsigned int addrLen)
@ -96,7 +97,15 @@ bool CNXDNNetwork::writeData(const unsigned char* data, unsigned int length, uns
if (m_debug)
CUtils::dump(1U, "NXDN Network Data Sent", buffer, 43U);
return m_socket.write(buffer, 43U, addr, addrLen);
switch (addr.ss_family) {
case AF_INET:
return m_socket4.write(buffer, 43U, addr, addrLen);
case AF_INET6:
return m_socket6.write(buffer, 43U, addr, addrLen);
default:
LogError("Unknown socket address family - %u", addr.ss_family);
return false;
}
}
bool CNXDNNetwork::writePoll(const sockaddr_storage& addr, unsigned int addrLen, unsigned short tg)
@ -118,7 +127,15 @@ bool CNXDNNetwork::writePoll(const sockaddr_storage& addr, unsigned int addrLen,
if (m_debug)
CUtils::dump(1U, "NXDN Network Poll Sent", data, 17U);
return m_socket.write(data, 17U, addr, addrLen);
switch (addr.ss_family) {
case AF_INET:
return m_socket4.write(data, 17U, addr, addrLen);
case AF_INET6:
return m_socket6.write(data, 17U, addr, addrLen);
default:
LogError("Unknown socket address family - %u", addr.ss_family);
return false;
}
}
bool CNXDNNetwork::writeUnlink(const sockaddr_storage& addr, unsigned int addrLen, unsigned short tg)
@ -140,7 +157,15 @@ bool CNXDNNetwork::writeUnlink(const sockaddr_storage& addr, unsigned int addrLe
if (m_debug)
CUtils::dump(1U, "NXDN Network Unlink Sent", data, 17U);
return m_socket.write(data, 17U, addr, addrLen);
switch (addr.ss_family) {
case AF_INET:
return m_socket4.write(data, 17U, addr, addrLen);
case AF_INET6:
return m_socket6.write(data, 17U, addr, addrLen);
default:
LogError("Unknown socket address family - %u", addr.ss_family);
return false;
}
}
unsigned int CNXDNNetwork::readData(unsigned char* data, unsigned int length, sockaddr_storage& addr, unsigned int& addrLen)
@ -148,7 +173,9 @@ unsigned int CNXDNNetwork::readData(unsigned char* data, unsigned int length, so
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;
@ -164,7 +191,8 @@ unsigned int CNXDNNetwork::readData(unsigned char* data, unsigned int length, so
void CNXDNNetwork::close()
{
m_socket.close();
m_socket4.close();
m_socket6.close();
LogInfo("Closing NXDN network connection");
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2014,2016,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2014,2016,2018,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

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2006-2016,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2006-2016,2020,2024 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -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;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2011,2013,2015,2016,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2011,2013,2015,2016,2020,2024 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -35,10 +35,6 @@
#include <ws2tcpip.h>
#endif
#if !defined(UDP_SOCKET_MAX)
#define UDP_SOCKET_MAX 1
#endif
enum IPMATCHTYPE {
IMT_ADDRESS_AND_PORT,
IMT_ADDRESS_ONLY
@ -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

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2015-2018,2020,2023,2024 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -19,6 +19,6 @@
#if !defined(VERSION_H)
#define VERSION_H
const char* VERSION = "20201105";
const char* VERSION = "20240129";
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2006-2016,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2006-2016,2020,2024 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -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;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2011,2013,2015,2016,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2011,2013,2015,2016,2020,2024 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -35,10 +35,6 @@
#include <ws2tcpip.h>
#endif
#if !defined(UDP_SOCKET_MAX)
#define UDP_SOCKET_MAX 1
#endif
enum IPMATCHTYPE {
IMT_ADDRESS_AND_PORT,
IMT_ADDRESS_ONLY
@ -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

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2018,2024 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -19,6 +19,6 @@
#if !defined(VERSION_H)
#define VERSION_H
const char* VERSION = "20201101";
const char* VERSION = "20240129";
#endif

View File

@ -1,287 +0,0 @@
/*
* Copyright (C) 2015,2016,2018,2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "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,
SECTION_ICOM_NETWORK,
SECTION_KENWOOD_NETWORK
};
CConf::CConf(const std::string& file) :
m_file(file),
m_tg(9999U),
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),
m_icomEnabled(false),
m_icomAddress(),
m_icomTGEnable(0U),
m_icomTGDisable(0U),
m_icomDebug(false),
m_kenwoodEnabled(false),
m_kenwoodAddress(),
m_kenwoodTGEnable(0U),
m_kenwoodTGDisable(0U),
m_kenwoodDebug(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 if (::strncmp(buffer, "[Icom Network]", 14U) == 0)
section = SECTION_ICOM_NETWORK;
else if (::strncmp(buffer, "[Kenwood Network]", 17U) == 0)
section = SECTION_KENWOOD_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 (::strcmp(key, "TG") == 0)
m_tg = (unsigned short)::atoi(value);
} 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;
} else if (section == SECTION_ICOM_NETWORK) {
if (::strcmp(key, "Enabled") == 0)
m_icomEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Address") == 0)
m_icomAddress = value;
else if (::strcmp(key, "TGEnable") == 0)
m_icomTGEnable = (unsigned short)::atoi(value);
else if (::strcmp(key, "TGDisable") == 0)
m_icomTGDisable = (unsigned short)::atoi(value);
else if (::strcmp(key, "Debug") == 0)
m_icomDebug = ::atoi(value) == 1;
} else if (section == SECTION_KENWOOD_NETWORK) {
if (::strcmp(key, "Enabled") == 0)
m_kenwoodEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Address") == 0)
m_kenwoodAddress = value;
else if (::strcmp(key, "TGEnable") == 0)
m_kenwoodTGEnable = (unsigned short)::atoi(value);
else if (::strcmp(key, "TGDisable") == 0)
m_kenwoodTGDisable = (unsigned short)::atoi(value);
else if (::strcmp(key, "Debug") == 0)
m_kenwoodDebug = ::atoi(value) == 1;
}
}
::fclose(fp);
return true;
}
bool CConf::getDaemon() const
{
return m_daemon;
}
unsigned short CConf::getTG() const
{
return m_tg;
}
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;
}
bool CConf::getIcomEnabled() const
{
return m_icomEnabled;
}
std::string CConf::getIcomAddress() const
{
return m_icomAddress;
}
unsigned short CConf::getIcomTGEnable() const
{
return m_icomTGEnable;
}
unsigned short CConf::getIcomTGDisable() const
{
return m_icomTGDisable;
}
bool CConf::getIcomDebug() const
{
return m_icomDebug;
}
bool CConf::getKenwoodEnabled() const
{
return m_kenwoodEnabled;
}
std::string CConf::getKenwoodAddress() const
{
return m_kenwoodAddress;
}
unsigned short CConf::getKenwoodTGEnable() const
{
return m_kenwoodTGEnable;
}
unsigned short CConf::getKenwoodTGDisable() const
{
return m_kenwoodTGDisable;
}
bool CConf::getKenwoodDebug() const
{
return m_kenwoodDebug;
}

View File

@ -1,96 +0,0 @@
/*
* Copyright (C) 2015,2016,2018,2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#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
unsigned short getTG() const;
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;
// The Icom Network section
bool getIcomEnabled() const;
std::string getIcomAddress() const;
unsigned short getIcomTGEnable() const;
unsigned short getIcomTGDisable() const;
bool getIcomDebug() const;
// The Kenwood Network section
bool getKenwoodEnabled() const;
std::string getKenwoodAddress() const;
unsigned short getKenwoodTGEnable() const;
unsigned short getKenwoodTGDisable() const;
bool getKenwoodDebug() const;
private:
std::string m_file;
unsigned short m_tg;
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;
bool m_icomEnabled;
std::string m_icomAddress;
unsigned short m_icomTGEnable;
unsigned short m_icomTGDisable;
bool m_icomDebug;
bool m_kenwoodEnabled;
std::string m_kenwoodAddress;
unsigned short m_kenwoodTGEnable;
unsigned short m_kenwoodTGDisable;
bool m_kenwoodDebug;
};
#endif

View File

@ -1,139 +0,0 @@
/*
* Copyright (C) 2009-2014,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 "IcomNetwork.h"
#include "Utils.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
const unsigned int BUFFER_LENGTH = 200U;
const unsigned int ICOM_PORT = 41300U;
CIcomNetwork::CIcomNetwork(const std::string& address, bool debug) :
m_socket(ICOM_PORT),
m_addr(),
m_addrLen(0U),
m_debug(debug)
{
assert(!address.empty());
if (CUDPSocket::lookup(address, ICOM_PORT, m_addr, m_addrLen) != 0)
m_addrLen = 0U;
}
CIcomNetwork::~CIcomNetwork()
{
}
bool CIcomNetwork::open()
{
if (m_addrLen == 0U) {
LogError("Unable to resolve the address of the Icom network");
return false;
}
bool ret = m_socket.open(m_addr);
if (!ret) {
LogError("Unable to open the Icom network connection");
return false;
}
LogMessage("Opened the Icom network connection");
return true;
}
bool CIcomNetwork::write(const unsigned char* data, unsigned int len)
{
assert(data != NULL);
unsigned char buffer[110U];
::memset(buffer, 0x00U, 110U);
buffer[0U] = 'I';
buffer[1U] = 'C';
buffer[2U] = 'O';
buffer[3U] = 'M';
buffer[4U] = 0x01U;
buffer[5U] = 0x01U;
buffer[6U] = 0x08U;
buffer[7U] = 0xE0U;
if ((data[9U] & 0x02U) == 0x02U) {
buffer[37U] = 0x23U;
buffer[38U] = 0x02U;
buffer[39U] = 0x18U;
} else {
buffer[37U] = 0x23U;
buffer[38U] = (data[9U] & 0x0CU) != 0x00U ? 0x1CU : 0x10U;
buffer[39U] = 0x21U;
}
::memcpy(buffer + 40U, data + 10U, 33U);
if (m_debug)
CUtils::dump(1U, "Icom Network Data Sent", buffer, 102U);
return m_socket.write(buffer, 102U, m_addr, m_addrLen);
}
unsigned int CIcomNetwork::read(unsigned char* data)
{
unsigned char buffer[BUFFER_LENGTH];
sockaddr_storage addr;
unsigned int addrLen;
int length = m_socket.read(buffer, BUFFER_LENGTH, addr, addrLen);
if (length <= 0)
return 0U;
// Check if the data is for us
if (!CUDPSocket::match(m_addr, addr)) {
LogMessage("Icom packet received from an invalid source");
return 0U;
}
// Invalid packet type?
if (::memcmp(buffer, "ICOM", 4U) != 0)
return 0U;
if (length != 102)
return 0U;
if (m_debug)
CUtils::dump(1U, "Icom Network Data Received", buffer, length);
::memcpy(data, buffer + 40U, 33U);
return 33U;
}
void CIcomNetwork::clock(unsigned int ms)
{
}
void CIcomNetwork::close()
{
m_socket.close();
LogMessage("Closing Icom network connection");
}

View File

@ -1,50 +0,0 @@
/*
* Copyright (C) 2009-2014,2016,2018,2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef IcomNetwork_H
#define IcomNetwork_H
#include "UDPSocket.h"
#include "Timer.h"
#include <cstdint>
#include <string>
class CIcomNetwork {
public:
CIcomNetwork(const std::string& address, bool debug);
~CIcomNetwork();
bool open();
bool write(const unsigned char* data, unsigned int len);
unsigned int read(unsigned char* data);
void close();
void clock(unsigned int ms);
private:
CUDPSocket m_socket;
sockaddr_storage m_addr;
unsigned int m_addrLen;
bool m_debug;
};
#endif

View File

@ -1,941 +0,0 @@
/*
* Copyright (C) 2009-2014,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 "KenwoodNetwork.h"
#include "NXDNCRC.h"
#include "Utils.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
#include <ctime>
const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U };
#define WRITE_BIT(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
#define READ_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
const unsigned int BUFFER_LENGTH = 200U;
const unsigned int RTP_PORT = 64000U;
const unsigned int RTCP_PORT = 64001U;
CKenwoodNetwork::CKenwoodNetwork(const std::string& address, bool debug) :
m_rtpSocket(RTP_PORT),
m_rtcpSocket(RTCP_PORT),
m_rtpAddr(),
m_rtpAddrLen(0U),
m_rtcpAddr(),
m_rtcpAddrLen(0U),
m_headerSeen(false),
m_seen1(false),
m_seen2(false),
m_seen3(false),
m_seen4(false),
m_sacch(NULL),
m_sessionId(1U),
m_seqNo(0U),
m_ssrc(0U),
m_debug(debug),
m_startSecs(0U),
m_startUSecs(0U),
m_rtcpTimer(1000U, 0U, 200U),
m_hangTimer(1000U, 5U),
m_hangType(0U),
m_hangSrc(0U),
m_hangDst(0U),
m_random()
{
assert(!address.empty());
m_sacch = new unsigned char[10U];
if (CUDPSocket::lookup(address, RTP_PORT, m_rtpAddr, m_rtpAddrLen) != 0)
m_rtpAddrLen = 0U;
if (CUDPSocket::lookup(address, RTCP_PORT, m_rtcpAddr, m_rtcpAddrLen) != 0)
m_rtcpAddrLen = 0U;
std::random_device rd;
std::mt19937 mt(rd());
m_random = mt;
}
CKenwoodNetwork::~CKenwoodNetwork()
{
delete[] m_sacch;
}
bool CKenwoodNetwork::open()
{
if (m_rtpAddrLen == 0U || m_rtcpAddrLen == 0U) {
LogError("Unable to resolve the address of the Kenwood network");
return false;
}
if (!m_rtcpSocket.open(m_rtcpAddr)) {
LogError("Unable to open the Kenwood network connection");
return false;
}
if (!m_rtpSocket.open(m_rtpAddr)) {
LogError("Unable to open the Kenwood network connection");
m_rtcpSocket.close();
return false;
}
LogMessage("Opened the Kenwood network connection");
std::uniform_int_distribution<unsigned int> dist(0x00000001, 0xfffffffe);
m_ssrc = dist(m_random);
return true;
}
bool CKenwoodNetwork::write(const unsigned char* data, unsigned int length)
{
assert(data != NULL);
switch (data[0U]) {
case 0x81U: // Voice header or trailer
case 0x83U:
return processIcomVoiceHeader(data);
case 0xACU: // Voice data
case 0xAEU:
return processIcomVoiceData(data);
default:
return false;
}
}
bool CKenwoodNetwork::processIcomVoiceHeader(const unsigned char* inData)
{
assert(inData != NULL);
unsigned char outData[30U];
::memset(outData, 0x00U, 30U);
// SACCH
outData[0U] = inData[2U];
outData[1U] = inData[1U];
outData[2U] = inData[4U] & 0xC0U;
outData[3U] = inData[3U];
// FACCH 1+2
outData[4U] = outData[14U] = inData[6U];
outData[5U] = outData[15U] = inData[5U];
outData[6U] = outData[16U] = inData[8U];
outData[7U] = outData[17U] = inData[7U];
outData[8U] = outData[18U] = inData[10U];
outData[9U] = outData[19U] = inData[9U];
outData[10U] = outData[20U] = inData[12U];
outData[11U] = outData[21U] = inData[11U];
unsigned short src = (inData[8U] << 8) + (inData[9U] << 0);
unsigned short dst = (inData[10U] << 8) + (inData[11U] << 0);
unsigned char type = (inData[7U] >> 5) & 0x07U;
switch (inData[5U] & 0x3FU) {
case 0x01U:
m_hangTimer.stop();
m_rtcpTimer.start();
writeRTCPStart();
return writeRTPVoiceHeader(outData);
case 0x08U: {
m_hangTimer.start();
bool ret = writeRTPVoiceTrailer(outData);
writeRTCPHang(type, src, dst);
return ret;
}
default:
return false;
}
}
bool CKenwoodNetwork::processIcomVoiceData(const unsigned char* inData)
{
assert(inData != NULL);
unsigned char outData[40U], temp[10U];
::memset(outData, 0x00U, 40U);
// SACCH
outData[0U] = inData[2U];
outData[1U] = inData[1U];
outData[2U] = inData[4U] & 0xC0U;
outData[3U] = inData[3U];
// Audio 1
::memset(temp, 0x00U, 10U);
for (unsigned int i = 0U; i < 49U; i++) {
unsigned int offset = (5U * 8U) + i;
bool b = READ_BIT(inData, offset);
WRITE_BIT(temp, i, b);
}
outData[4U] = temp[1U];
outData[5U] = temp[0U];
outData[6U] = temp[3U];
outData[7U] = temp[2U];
outData[8U] = temp[5U];
outData[9U] = temp[4U];
outData[10U] = temp[7U];
outData[11U] = temp[6U];
// Audio 2
::memset(temp, 0x00U, 10U);
for (unsigned int i = 0U; i < 49U; i++) {
unsigned int offset = (5U * 8U) + 49U + i;
bool b = READ_BIT(inData, offset);
WRITE_BIT(temp, i, b);
}
outData[12U] = temp[1U];
outData[13U] = temp[0U];
outData[14U] = temp[3U];
outData[15U] = temp[2U];
outData[16U] = temp[5U];
outData[17U] = temp[4U];
outData[18U] = temp[7U];
outData[19U] = temp[6U];
// Audio 3
::memset(temp, 0x00U, 10U);
for (unsigned int i = 0U; i < 49U; i++) {
unsigned int offset = (19U * 8U) + i;
bool b = READ_BIT(inData, offset);
WRITE_BIT(temp, i, b);
}
outData[20U] = temp[1U];
outData[21U] = temp[0U];
outData[22U] = temp[3U];
outData[23U] = temp[2U];
outData[24U] = temp[5U];
outData[25U] = temp[4U];
outData[26U] = temp[7U];
outData[27U] = temp[6U];
// Audio 4
::memset(temp, 0x00U, 10U);
for (unsigned int i = 0U; i < 49U; i++) {
unsigned int offset = (19U * 8U) + 49U + i;
bool b = READ_BIT(inData, offset);
WRITE_BIT(temp, i, b);
}
outData[28U] = temp[1U];
outData[29U] = temp[0U];
outData[30U] = temp[3U];
outData[31U] = temp[2U];
outData[32U] = temp[5U];
outData[33U] = temp[4U];
outData[34U] = temp[7U];
outData[35U] = temp[6U];
return writeRTPVoiceData(outData);
}
bool CKenwoodNetwork::writeRTPVoiceHeader(const unsigned char* data)
{
assert(data != NULL);
unsigned char buffer[50U];
::memset(buffer, 0x00U, 50U);
buffer[0U] = 0x80U;
buffer[1U] = 0x66U;
m_seqNo++;
buffer[2U] = (m_seqNo >> 8) & 0xFFU;
buffer[3U] = (m_seqNo >> 0) & 0xFFU;
unsigned long timeStamp = getTimeStamp();
buffer[4U] = (timeStamp >> 24) & 0xFFU;
buffer[5U] = (timeStamp >> 16) & 0xFFU;
buffer[6U] = (timeStamp >> 8) & 0xFFU;
buffer[7U] = (timeStamp >> 0) & 0xFFU;
buffer[8U] = (m_ssrc >> 24) & 0xFFU;
buffer[9U] = (m_ssrc >> 16) & 0xFFU;
buffer[10U] = (m_ssrc >> 8) & 0xFFU;
buffer[11U] = (m_ssrc >> 0) & 0xFFU;
m_sessionId++;
buffer[12U] = m_sessionId;
buffer[13U] = 0x00U;
buffer[14U] = 0x00U;
buffer[15U] = 0x00U;
buffer[16U] = 0x03U;
buffer[17U] = 0x03U;
buffer[18U] = 0x04U;
buffer[19U] = 0x04U;
buffer[20U] = 0x0AU;
buffer[21U] = 0x05U;
buffer[22U] = 0x0AU;
::memcpy(buffer + 23U, data, 24U);
if (m_debug)
CUtils::dump(1U, "Kenwood Network RTP Data Sent", buffer, 47U);
return m_rtpSocket.write(buffer, 47U, m_rtpAddr, m_rtpAddrLen);
}
bool CKenwoodNetwork::writeRTPVoiceTrailer(const unsigned char* data)
{
assert(data != NULL);
unsigned char buffer[50U];
::memset(buffer, 0x00U, 50U);
buffer[0U] = 0x80U;
buffer[1U] = 0x66U;
m_seqNo++;
buffer[2U] = (m_seqNo >> 8) & 0xFFU;
buffer[3U] = (m_seqNo >> 0) & 0xFFU;
unsigned long timeStamp = getTimeStamp();
buffer[4U] = (timeStamp >> 24) & 0xFFU;
buffer[5U] = (timeStamp >> 16) & 0xFFU;
buffer[6U] = (timeStamp >> 8) & 0xFFU;
buffer[7U] = (timeStamp >> 0) & 0xFFU;
buffer[8U] = (m_ssrc >> 24) & 0xFFU;
buffer[9U] = (m_ssrc >> 16) & 0xFFU;
buffer[10U] = (m_ssrc >> 8) & 0xFFU;
buffer[11U] = (m_ssrc >> 0) & 0xFFU;
buffer[12U] = m_sessionId;
buffer[13U] = 0x00U;
buffer[14U] = 0x00U;
buffer[15U] = 0x00U;
buffer[16U] = 0x03U;
buffer[17U] = 0x03U;
buffer[18U] = 0x04U;
buffer[19U] = 0x04U;
buffer[20U] = 0x0AU;
buffer[21U] = 0x05U;
buffer[22U] = 0x0AU;
::memcpy(buffer + 23U, data, 24U);
if (m_debug)
CUtils::dump(1U, "Kenwood Network RTP Data Sent", buffer, 47U);
return m_rtpSocket.write(buffer, 47U, m_rtpAddr, m_rtpAddrLen);
}
bool CKenwoodNetwork::writeRTPVoiceData(const unsigned char* data)
{
assert(data != NULL);
unsigned char buffer[60U];
::memset(buffer, 0x00U, 60U);
buffer[0U] = 0x80U;
buffer[1U] = 0x66U;
m_seqNo++;
buffer[2U] = (m_seqNo >> 8) & 0xFFU;
buffer[3U] = (m_seqNo >> 0) & 0xFFU;
unsigned long timeStamp = getTimeStamp();
buffer[4U] = (timeStamp >> 24) & 0xFFU;
buffer[5U] = (timeStamp >> 16) & 0xFFU;
buffer[6U] = (timeStamp >> 8) & 0xFFU;
buffer[7U] = (timeStamp >> 0) & 0xFFU;
buffer[8U] = (m_ssrc >> 24) & 0xFFU;
buffer[9U] = (m_ssrc >> 16) & 0xFFU;
buffer[10U] = (m_ssrc >> 8) & 0xFFU;
buffer[11U] = (m_ssrc >> 0) & 0xFFU;
buffer[12U] = m_sessionId;
buffer[13U] = 0x00U;
buffer[14U] = 0x00U;
buffer[15U] = 0x00U;
buffer[16U] = 0x03U;
buffer[17U] = 0x02U;
buffer[18U] = 0x04U;
buffer[19U] = 0x07U;
buffer[20U] = 0x10U;
buffer[21U] = 0x08U;
buffer[22U] = 0x10U;
::memcpy(buffer + 23U, data, 36U);
if (m_debug)
CUtils::dump(1U, "Kenwood Network RTP Data Sent", buffer, 59U);
return m_rtpSocket.write(buffer, 59U, m_rtpAddr, m_rtpAddrLen);
}
bool CKenwoodNetwork::writeRTCPStart()
{
#if defined(_WIN32) || defined(_WIN64)
time_t now;
::time(&now);
m_startSecs = uint32_t(now);
SYSTEMTIME st;
::GetSystemTime(&st);
m_startUSecs = st.wMilliseconds * 1000U;
#else
struct timeval tod;
::gettimeofday(&tod, NULL);
m_startSecs = tod.tv_sec;
m_startUSecs = tod.tv_usec;
#endif
unsigned char buffer[30U];
::memset(buffer, 0x00U, 30U);
buffer[0U] = 0x8AU;
buffer[1U] = 0xCCU;
buffer[2U] = 0x00U;
buffer[3U] = 0x06U;
buffer[4U] = (m_ssrc >> 24) & 0xFFU;
buffer[5U] = (m_ssrc >> 16) & 0xFFU;
buffer[6U] = (m_ssrc >> 8) & 0xFFU;
buffer[7U] = (m_ssrc >> 0) & 0xFFU;
buffer[8U] = 'K';
buffer[9U] = 'W';
buffer[10U] = 'N';
buffer[11U] = 'E';
buffer[12U] = (m_startSecs >> 24) & 0xFFU;
buffer[13U] = (m_startSecs >> 16) & 0xFFU;
buffer[14U] = (m_startSecs >> 8) & 0xFFU;
buffer[15U] = (m_startSecs >> 0) & 0xFFU;
buffer[16U] = (m_startUSecs >> 24) & 0xFFU;
buffer[17U] = (m_startUSecs >> 16) & 0xFFU;
buffer[18U] = (m_startUSecs >> 8) & 0xFFU;
buffer[19U] = (m_startUSecs >> 0) & 0xFFU;
buffer[22U] = 0x02U;
buffer[24U] = 0x01U;
buffer[27U] = 0x0AU;
if (m_debug)
CUtils::dump(1U, "Kenwood Network RTCP Data Sent", buffer, 28U);
return m_rtcpSocket.write(buffer, 28U, m_rtcpAddr, m_rtcpAddrLen);
}
bool CKenwoodNetwork::writeRTCPPing()
{
unsigned char buffer[30U];
::memset(buffer, 0x00U, 30U);
buffer[0U] = 0x8AU;
buffer[1U] = 0xCCU;
buffer[2U] = 0x00U;
buffer[3U] = 0x06U;
buffer[4U] = (m_ssrc >> 24) & 0xFFU;
buffer[5U] = (m_ssrc >> 16) & 0xFFU;
buffer[6U] = (m_ssrc >> 8) & 0xFFU;
buffer[7U] = (m_ssrc >> 0) & 0xFFU;
buffer[8U] = 'K';
buffer[9U] = 'W';
buffer[10U] = 'N';
buffer[11U] = 'E';
buffer[12U] = (m_startSecs >> 24) & 0xFFU;
buffer[13U] = (m_startSecs >> 16) & 0xFFU;
buffer[14U] = (m_startSecs >> 8) & 0xFFU;
buffer[15U] = (m_startSecs >> 0) & 0xFFU;
buffer[16U] = (m_startUSecs >> 24) & 0xFFU;
buffer[17U] = (m_startUSecs >> 16) & 0xFFU;
buffer[18U] = (m_startUSecs >> 8) & 0xFFU;
buffer[19U] = (m_startUSecs >> 0) & 0xFFU;
buffer[22U] = 0x02U;
buffer[24U] = 0x01U;
buffer[27U] = 0x7BU;
if (m_debug)
CUtils::dump(1U, "Kenwood Network RTCP Data Sent", buffer, 28U);
return m_rtcpSocket.write(buffer, 28U, m_rtcpAddr, m_rtcpAddrLen);
}
bool CKenwoodNetwork::writeRTCPHang(unsigned char type, unsigned short src, unsigned short dst)
{
m_hangType = type;
m_hangSrc = src;
m_hangDst = dst;
return writeRTCPHang();
}
bool CKenwoodNetwork::writeRTCPHang()
{
unsigned char buffer[30U];
::memset(buffer, 0x00U, 30U);
buffer[0U] = 0x8BU;
buffer[1U] = 0xCCU;
buffer[2U] = 0x00U;
buffer[3U] = 0x04U;
buffer[4U] = (m_ssrc >> 24) & 0xFFU;
buffer[5U] = (m_ssrc >> 16) & 0xFFU;
buffer[6U] = (m_ssrc >> 8) & 0xFFU;
buffer[7U] = (m_ssrc >> 0) & 0xFFU;
buffer[8U] = 'K';
buffer[9U] = 'W';
buffer[10U] = 'N';
buffer[11U] = 'E';
buffer[12U] = (m_hangSrc >> 8) & 0xFFU;
buffer[13U] = (m_hangSrc >> 0) & 0xFFU;
buffer[14U] = (m_hangDst >> 8) & 0xFFU;
buffer[15U] = (m_hangDst >> 0) & 0xFFU;
buffer[16U] = m_hangType;
if (m_debug)
CUtils::dump(1U, "Kenwood Network RTCP Data Sent", buffer, 20U);
return m_rtcpSocket.write(buffer, 20U, m_rtcpAddr, m_rtcpAddrLen);
}
unsigned int CKenwoodNetwork::read(unsigned char* data)
{
assert(data != NULL);
unsigned char dummy[BUFFER_LENGTH];
readRTCP(dummy);
unsigned int len = readRTP(data);
switch (len) {
case 0U: // Nothing received
return 0U;
case 35U: // Voice header or trailer
return processKenwoodVoiceHeader(data);
case 47U: // Voice data
if (m_headerSeen)
return processKenwoodVoiceData(data);
else
return processKenwoodVoiceLateEntry(data);
case 31U: // Data
return processKenwoodData(data);
default:
CUtils::dump(5U, "Unknown data received from the Kenwood network", data, len);
return 0U;
}
}
unsigned int CKenwoodNetwork::readRTP(unsigned char* data)
{
assert(data != NULL);
unsigned char buffer[BUFFER_LENGTH];
sockaddr_storage addr;
unsigned int addrLen;
int length = m_rtpSocket.read(buffer, BUFFER_LENGTH, addr, addrLen);
if (length <= 0)
return 0U;
// Check if the data is for us
if (!CUDPSocket::match(m_rtpAddr, addr, IMT_ADDRESS_ONLY)) {
LogMessage("Kenwood RTP packet received from an invalid source");
return 0U;
}
if (m_debug)
CUtils::dump(1U, "Kenwood Network RTP Data Received", buffer, length);
::memcpy(data, buffer + 12U, length - 12U);
return length - 12U;
}
unsigned int CKenwoodNetwork::readRTCP(unsigned char* data)
{
assert(data != NULL);
unsigned char buffer[BUFFER_LENGTH];
sockaddr_storage addr;
unsigned int addrLen;
int length = m_rtcpSocket.read(buffer, BUFFER_LENGTH, addr, addrLen);
if (length <= 0)
return 0U;
// Check if the data is for us
if (!CUDPSocket::match(m_rtcpAddr, addr, IMT_ADDRESS_ONLY)) {
LogMessage("Kenwood RTCP packet received from an invalid source");
return 0U;
}
if (m_debug)
CUtils::dump(1U, "Kenwood Network RTCP Data Received", buffer, length);
if (::memcmp(buffer + 8U, "KWNE", 4U) != 0) {
LogError("Missing RTCP KWNE signature");
return 0U;
}
::memcpy(data, buffer + 12U, length - 12U);
return length - 12U;
}
void CKenwoodNetwork::close()
{
m_rtcpSocket.close();
m_rtpSocket.close();
LogMessage("Closing Kenwood connection");
}
void CKenwoodNetwork::clock(unsigned int ms)
{
m_rtcpTimer.clock(ms);
if (m_rtcpTimer.isRunning() && m_rtcpTimer.hasExpired()) {
if (m_hangTimer.isRunning())
writeRTCPHang();
else
writeRTCPPing();
m_rtcpTimer.start();
}
m_hangTimer.clock(ms);
if (m_hangTimer.isRunning() && m_hangTimer.hasExpired()) {
m_rtcpTimer.stop();
m_hangTimer.stop();
}
}
unsigned int CKenwoodNetwork::processKenwoodVoiceHeader(unsigned char* inData)
{
assert(inData != NULL);
unsigned char outData[50U], temp[20U];
::memset(outData, 0x00U, 50U);
// LICH
outData[0U] = 0x83U;
// SACCH
::memset(temp, 0x00U, 20U);
temp[0U] = inData[12U];
temp[1U] = inData[11U];
temp[2U] = inData[14U];
temp[3U] = inData[13U];
CNXDNCRC::encodeCRC6(temp, 26U);
::memcpy(outData + 1U, temp, 4U);
// FACCH 1+2
::memset(temp, 0x00U, 20U);
temp[0U] = inData[16U];
temp[1U] = inData[15U];
temp[2U] = inData[18U];
temp[3U] = inData[17U];
temp[4U] = inData[20U];
temp[5U] = inData[19U];
temp[6U] = inData[22U];
temp[7U] = inData[21U];
temp[8U] = inData[24U];
temp[9U] = inData[23U];
CNXDNCRC::encodeCRC12(temp, 80U);
::memcpy(outData + 5U, temp, 12U);
::memcpy(outData + 19U, temp, 12U);
switch (outData[5U] & 0x3FU) {
case 0x01U:
::memcpy(inData, outData, 33U);
m_headerSeen = true;
m_seen1 = false;
m_seen2 = false;
m_seen3 = false;
m_seen4 = false;
return 33U;
case 0x08U:
::memcpy(inData, outData, 33U);
m_headerSeen = false;
m_seen1 = false;
m_seen2 = false;
m_seen3 = false;
m_seen4 = false;
return 33U;
default:
return 0U;
}
}
unsigned int CKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData)
{
assert(inData != NULL);
unsigned char outData[50U], temp[20U];
::memset(outData, 0x00U, 50U);
// LICH
outData[0U] = 0xAEU;
// SACCH
::memset(temp, 0x00U, 20U);
temp[0U] = inData[12U];
temp[1U] = inData[11U];
temp[2U] = inData[14U];
temp[3U] = inData[13U];
CNXDNCRC::encodeCRC6(temp, 26U);
::memcpy(outData + 1U, temp, 4U);
// AMBE 1+2
unsigned int n = 5U * 8U;
temp[0U] = inData[16U];
temp[1U] = inData[15U];
temp[2U] = inData[18U];
temp[3U] = inData[17U];
temp[4U] = inData[20U];
temp[5U] = inData[19U];
temp[6U] = inData[22U];
temp[7U] = inData[21U];
for (unsigned int i = 0U; i < 49U; i++, n++) {
bool b = READ_BIT(temp, i);
WRITE_BIT(outData, n, b);
}
temp[0U] = inData[24U];
temp[1U] = inData[23U];
temp[2U] = inData[26U];
temp[3U] = inData[25U];
temp[4U] = inData[28U];
temp[5U] = inData[27U];
temp[6U] = inData[30U];
temp[7U] = inData[29U];
for (unsigned int i = 0U; i < 49U; i++, n++) {
bool b = READ_BIT(temp, i);
WRITE_BIT(outData, n, b);
}
// AMBE 3+4
n = 19U * 8U;
temp[0U] = inData[32U];
temp[1U] = inData[31U];
temp[2U] = inData[34U];
temp[3U] = inData[33U];
temp[4U] = inData[36U];
temp[5U] = inData[35U];
temp[6U] = inData[38U];
temp[7U] = inData[37U];
for (unsigned int i = 0U; i < 49U; i++, n++) {
bool b = READ_BIT(temp, i);
WRITE_BIT(outData, n, b);
}
temp[0U] = inData[40U];
temp[1U] = inData[39U];
temp[2U] = inData[42U];
temp[3U] = inData[41U];
temp[4U] = inData[44U];
temp[5U] = inData[43U];
temp[6U] = inData[46U];
temp[7U] = inData[45U];
for (unsigned int i = 0U; i < 49U; i++, n++) {
bool b = READ_BIT(temp, i);
WRITE_BIT(outData, n, b);
}
::memcpy(inData, outData, 33U);
return 33U;
}
unsigned int CKenwoodNetwork::processKenwoodData(unsigned char* inData)
{
if (inData[7U] != 0x09U && inData[7U] != 0x0BU && inData[7U] != 0x08U)
return 0U;
unsigned char outData[50U];
if (inData[7U] == 0x09U || inData[7U] == 0x08U) {
outData[0U] = 0x90U;
outData[1U] = inData[8U];
outData[2U] = inData[7U];
outData[3U] = inData[10U];
outData[4U] = inData[9U];
outData[5U] = inData[12U];
outData[6U] = inData[11U];
::memcpy(inData, outData, 7U);
return 7U;
} else {
outData[0U] = 0x90U;
outData[1U] = inData[8U];
outData[2U] = inData[7U];
outData[3U] = inData[10U];
outData[4U] = inData[9U];
outData[5U] = inData[12U];
outData[6U] = inData[11U];
outData[7U] = inData[14U];
outData[8U] = inData[13U];
outData[9U] = inData[16U];
outData[10U] = inData[15U];
outData[11U] = inData[18U];
outData[12U] = inData[17U];
outData[13U] = inData[20U];
outData[14U] = inData[19U];
outData[15U] = inData[22U];
outData[16U] = inData[21U];
outData[17U] = inData[24U];
outData[18U] = inData[23U];
outData[19U] = inData[26U];
outData[20U] = inData[25U];
outData[21U] = inData[28U];
outData[22U] = inData[27U];
outData[23U] = inData[29U];
::memcpy(inData, outData, 24U);
return 24U;
}
}
unsigned long CKenwoodNetwork::getTimeStamp() const
{
unsigned long timeStamp = 0UL;
#if defined(_WIN32) || defined(_WIN64)
SYSTEMTIME st;
::GetSystemTime(&st);
unsigned int hh = st.wHour;
unsigned int mm = st.wMinute;
unsigned int ss = st.wSecond;
unsigned int ms = st.wMilliseconds;
timeStamp += hh * 3600U * 1000U * 80U;
timeStamp += mm * 60U * 1000U * 80U;
timeStamp += ss * 1000U * 80U;
timeStamp += ms * 80U;
#else
struct timeval tod;
::gettimeofday(&tod, NULL);
unsigned int ss = tod.tv_sec;
unsigned int ms = tod.tv_usec / 1000U;
timeStamp += ss * 1000U * 80U;
timeStamp += ms * 80U;
#endif
return timeStamp;
}
unsigned int CKenwoodNetwork::processKenwoodVoiceLateEntry(unsigned char* inData)
{
assert(inData != NULL);
unsigned char sacch[4U];
sacch[0U] = inData[12U];
sacch[1U] = inData[11U];
sacch[2U] = inData[14U];
sacch[3U] = inData[13U];
switch (sacch[0U] & 0xC0U) {
case 0xC0U:
if (!m_seen1) {
unsigned int offset = 0U;
for (unsigned int i = 8U; i < 26U; i++, offset++) {
bool b = READ_BIT(sacch, i) != 0U;
WRITE_BIT(m_sacch, offset, b);
}
m_seen1 = true;
}
break;
case 0x80U:
if (!m_seen2) {
unsigned int offset = 18U;
for (unsigned int i = 8U; i < 26U; i++, offset++) {
bool b = READ_BIT(sacch, i) != 0U;
WRITE_BIT(m_sacch, offset, b);
}
m_seen2 = true;
}
break;
case 0x40U:
if (!m_seen3) {
unsigned int offset = 36U;
for (unsigned int i = 8U; i < 26U; i++, offset++) {
bool b = READ_BIT(sacch, i) != 0U;
WRITE_BIT(m_sacch, offset, b);
}
m_seen3 = true;
}
break;
case 0x00U:
if (!m_seen4) {
unsigned int offset = 54U;
for (unsigned int i = 8U; i < 26U; i++, offset++) {
bool b = READ_BIT(sacch, i) != 0U;
WRITE_BIT(m_sacch, offset, b);
}
m_seen4 = true;
}
break;
}
if (!m_seen1 || !m_seen2 || !m_seen3 || !m_seen4)
return 0U;
// Create a dummy header
// Header SACCH
inData[11U] = 0x10U;
inData[12U] = 0x01U;
inData[13U] = 0x00U;
inData[14U] = 0x00U;
// Header FACCH
inData[15U] = m_sacch[1U];
inData[16U] = m_sacch[0U];
inData[17U] = m_sacch[3U];
inData[18U] = m_sacch[2U];
inData[19U] = m_sacch[5U];
inData[20U] = m_sacch[4U];
inData[21U] = m_sacch[7U];
inData[22U] = m_sacch[6U];
inData[23U] = 0x00U;
inData[24U] = m_sacch[8U];
return processKenwoodVoiceHeader(inData);
}

View File

@ -1,88 +0,0 @@
/*
* Copyright (C) 2009-2014,2016,2018,2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef KenwoodNetwork_H
#define KenwoodNetwork_H
#include "UDPSocket.h"
#include "Timer.h"
#include <cstdint>
#include <string>
#include <random>
class CKenwoodNetwork {
public:
CKenwoodNetwork(const std::string& address, bool debug);
~CKenwoodNetwork();
bool open();
bool write(const unsigned char* data, unsigned int length);
unsigned int read(unsigned char* data);
void close();
void clock(unsigned int ms);
private:
CUDPSocket m_rtpSocket;
CUDPSocket m_rtcpSocket;
sockaddr_storage m_rtpAddr;
unsigned int m_rtpAddrLen;
sockaddr_storage m_rtcpAddr;
unsigned int m_rtcpAddrLen;
bool m_headerSeen;
bool m_seen1;
bool m_seen2;
bool m_seen3;
bool m_seen4;
unsigned char* m_sacch;
uint8_t m_sessionId;
uint16_t m_seqNo;
unsigned int m_ssrc;
bool m_debug;
uint32_t m_startSecs;
uint32_t m_startUSecs;
CTimer m_rtcpTimer;
CTimer m_hangTimer;
unsigned char m_hangType;
unsigned short m_hangSrc;
unsigned short m_hangDst;
std::mt19937 m_random;
bool processIcomVoiceHeader(const unsigned char* data);
bool processIcomVoiceData(const unsigned char* data);
unsigned int processKenwoodVoiceHeader(unsigned char* data);
unsigned int processKenwoodVoiceData(unsigned char* data);
unsigned int processKenwoodVoiceLateEntry(unsigned char* data);
unsigned int processKenwoodData(unsigned char* data);
bool writeRTPVoiceHeader(const unsigned char* data);
bool writeRTPVoiceData(const unsigned char* data);
bool writeRTPVoiceTrailer(const unsigned char* data);
bool writeRTCPStart();
bool writeRTCPPing();
bool writeRTCPHang(unsigned char type, unsigned short src, unsigned short dst);
bool writeRTCPHang();
unsigned int readRTP(unsigned char* data);
unsigned int readRTCP(unsigned char* data);
unsigned long getTimeStamp() const;
};
#endif

View File

@ -1,192 +0,0 @@
/*
* Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Log.h"
#if defined(_WIN32) || defined(_WIN64)
#include <Windows.h>
#else
#include <sys/time.h>
#include <unistd.h>
#endif
#include <cstdio>
#include <cstdlib>
#include <cstdarg>
#include <ctime>
#include <cassert>
#include <cstring>
static unsigned int m_fileLevel = 2U;
static std::string m_filePath;
static std::string m_fileRoot;
static bool m_fileRotate = true;
static FILE* m_fpLog = NULL;
static bool m_daemon = false;
static unsigned int m_displayLevel = 2U;
static struct tm m_tm;
static char LEVELS[] = " DMIWEF";
static bool logOpenRotate()
{
bool status = false;
if (m_fileLevel == 0U)
return true;
time_t now;
::time(&now);
struct tm* tm = ::gmtime(&now);
if (tm->tm_mday == m_tm.tm_mday && tm->tm_mon == m_tm.tm_mon && tm->tm_year == m_tm.tm_year) {
if (m_fpLog != NULL)
return true;
} else {
if (m_fpLog != NULL)
::fclose(m_fpLog);
}
char filename[200U];
#if defined(_WIN32) || defined(_WIN64)
::sprintf(filename, "%s\\%s-%04d-%02d-%02d.log", m_filePath.c_str(), m_fileRoot.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
#else
::sprintf(filename, "%s/%s-%04d-%02d-%02d.log", m_filePath.c_str(), m_fileRoot.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
#endif
if ((m_fpLog = ::fopen(filename, "a+t")) != NULL) {
status = true;
#if !defined(_WIN32) && !defined(_WIN64)
if (m_daemon)
dup2(fileno(m_fpLog), fileno(stderr));
#endif
}
m_tm = *tm;
return status;
}
static bool logOpenNoRotate()
{
bool status = false;
if (m_fileLevel == 0U)
return true;
if (m_fpLog != NULL)
return true;
char filename[200U];
#if defined(_WIN32) || defined(_WIN64)
::sprintf(filename, "%s\\%s.log", m_filePath.c_str(), m_fileRoot.c_str());
#else
::sprintf(filename, "%s/%s.log", m_filePath.c_str(), m_fileRoot.c_str());
#endif
if ((m_fpLog = ::fopen(filename, "a+t")) != NULL) {
status = true;
#if !defined(_WIN32) && !defined(_WIN64)
if (m_daemon)
dup2(fileno(m_fpLog), fileno(stderr));
#endif
}
return status;
}
bool LogOpen()
{
if (m_fileRotate)
return logOpenRotate();
else
return logOpenNoRotate();
}
bool LogInitialise(bool daemon, const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel, bool rotate)
{
m_filePath = filePath;
m_fileRoot = fileRoot;
m_fileLevel = fileLevel;
m_displayLevel = displayLevel;
m_daemon = daemon;
m_fileRotate = rotate;
if (m_daemon)
m_displayLevel = 0U;
return ::LogOpen();
}
void LogFinalise()
{
if (m_fpLog != NULL)
::fclose(m_fpLog);
}
void Log(unsigned int level, const char* fmt, ...)
{
assert(fmt != NULL);
char buffer[501U];
#if defined(_WIN32) || defined(_WIN64)
SYSTEMTIME st;
::GetSystemTime(&st);
::sprintf(buffer, "%c: %04u-%02u-%02u %02u:%02u:%02u.%03u ", LEVELS[level], st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
#else
struct timeval now;
::gettimeofday(&now, NULL);
struct tm* tm = ::gmtime(&now.tv_sec);
::sprintf(buffer, "%c: %04d-%02d-%02d %02d:%02d:%02d.%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;
va_start(vl, fmt);
::vsnprintf(buffer + ::strlen(buffer), 500, fmt, vl);
va_end(vl);
if (level >= m_fileLevel && m_fileLevel != 0U) {
bool ret = ::LogOpen();
if (!ret)
return;
::fprintf(m_fpLog, "%s\n", buffer);
::fflush(m_fpLog);
}
if (level >= m_displayLevel && m_displayLevel != 0U) {
::fprintf(stdout, "%s\n", buffer);
::fflush(stdout);
}
if (level == 6U) { // Fatal
::fclose(m_fpLog);
exit(1);
}
}

View File

@ -1,36 +0,0 @@
/*
* Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(LOG_H)
#define LOG_H
#include <string>
#define LogDebug(fmt, ...) Log(1U, fmt, ##__VA_ARGS__)
#define LogMessage(fmt, ...) Log(2U, fmt, ##__VA_ARGS__)
#define LogInfo(fmt, ...) Log(3U, fmt, ##__VA_ARGS__)
#define LogWarning(fmt, ...) Log(4U, fmt, ##__VA_ARGS__)
#define LogError(fmt, ...) Log(5U, fmt, ##__VA_ARGS__)
#define LogFatal(fmt, ...) Log(6U, fmt, ##__VA_ARGS__)
extern void Log(unsigned int level, const char* fmt, ...);
extern bool LogInitialise(bool daemon, const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel, bool rotate);
extern void LogFinalise();
#endif

View File

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

View File

@ -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

View File

@ -1,45 +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 <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

File diff suppressed because it is too large Load Diff

View File

@ -1,185 +0,0 @@
/*
* Copyright (C) 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 "NXDNCRC.h"
#include <cstdio>
#include <cassert>
const uint8_t BIT_MASK_TABLE1[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U };
#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE1[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE1[(i)&7])
#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE1[(i)&7])
bool CNXDNCRC::checkCRC6(const unsigned char* in, unsigned int length)
{
assert(in != NULL);
uint8_t crc = createCRC6(in, length);
uint8_t temp[1U];
temp[0U] = 0x00U;
unsigned int j = length;
for (unsigned int i = 2U; i < 8U; i++, j++) {
bool b = READ_BIT1(in, j);
WRITE_BIT1(temp, i, b);
}
return crc == temp[0U];
}
void CNXDNCRC::encodeCRC6(unsigned char* in, unsigned int length)
{
assert(in != NULL);
uint8_t crc[1U];
crc[0U] = createCRC6(in, length);
unsigned int n = length;
for (unsigned int i = 2U; i < 8U; i++, n++) {
bool b = READ_BIT1(crc, i);
WRITE_BIT1(in, n, b);
}
}
bool CNXDNCRC::checkCRC12(const unsigned char* in, unsigned int length)
{
assert(in != NULL);
uint16_t crc = createCRC12(in, length);
uint8_t temp1[2U];
temp1[0U] = (crc >> 8) & 0xFFU;
temp1[1U] = (crc >> 0) & 0xFFU;
uint8_t temp2[2U];
temp2[0U] = 0x00U;
temp2[1U] = 0x00U;
unsigned int j = length;
for (unsigned int i = 4U; i < 16U; i++, j++) {
bool b = READ_BIT1(in, j);
WRITE_BIT1(temp2, i, b);
}
return temp1[0U] == temp2[0U] && temp1[1U] == temp2[1U];
}
void CNXDNCRC::encodeCRC12(unsigned char* in, unsigned int length)
{
assert(in != NULL);
uint16_t crc = createCRC12(in, length);
uint8_t temp[2U];
temp[0U] = (crc >> 8) & 0xFFU;
temp[1U] = (crc >> 0) & 0xFFU;
unsigned int n = length;
for (unsigned int i = 4U; i < 16U; i++, n++) {
bool b = READ_BIT1(temp, i);
WRITE_BIT1(in, n, b);
}
}
bool CNXDNCRC::checkCRC15(const unsigned char* in, unsigned int length)
{
assert(in != NULL);
uint16_t crc = createCRC15(in, length);
uint8_t temp1[2U];
temp1[0U] = (crc >> 8) & 0xFFU;
temp1[1U] = (crc >> 0) & 0xFFU;
uint8_t temp2[2U];
temp2[0U] = 0x00U;
temp2[1U] = 0x00U;
unsigned int j = length;
for (unsigned int i = 1U; i < 16U; i++, j++) {
bool b = READ_BIT1(in, j);
WRITE_BIT1(temp2, i, b);
}
return temp1[0U] == temp2[0U] && temp1[1U] == temp2[1U];
}
void CNXDNCRC::encodeCRC15(unsigned char* in, unsigned int length)
{
assert(in != NULL);
uint16_t crc = createCRC15(in, length);
uint8_t temp[2U];
temp[0U] = (crc >> 8) & 0xFFU;
temp[1U] = (crc >> 0) & 0xFFU;
unsigned int n = length;
for (unsigned int i = 1U; i < 16U; i++, n++) {
bool b = READ_BIT1(temp, i);
WRITE_BIT1(in, n, b);
}
}
uint8_t CNXDNCRC::createCRC6(const unsigned char* in, unsigned int length)
{
uint8_t crc = 0x3FU;
for (unsigned int i = 0U; i < length; i++) {
bool bit1 = READ_BIT1(in, i) != 0x00U;
bool bit2 = (crc & 0x20U) == 0x20U;
crc <<= 1;
if (bit1 ^ bit2)
crc ^= 0x27U;
}
return crc & 0x3FU;
}
uint16_t CNXDNCRC::createCRC12(const unsigned char* in, unsigned int length)
{
uint16_t crc = 0x0FFFU;
for (unsigned int i = 0U; i < length; i++) {
bool bit1 = READ_BIT1(in, i) != 0x00U;
bool bit2 = (crc & 0x0800U) == 0x0800U;
crc <<= 1;
if (bit1 ^ bit2)
crc ^= 0x080FU;
}
return crc & 0x0FFFU;
}
uint16_t CNXDNCRC::createCRC15(const unsigned char* in, unsigned int length)
{
uint16_t crc = 0x7FFFU;
for (unsigned int i = 0U; i < length; i++) {
bool bit1 = READ_BIT1(in, i) != 0x00U;
bool bit2 = (crc & 0x4000U) == 0x4000U;
crc <<= 1;
if (bit1 ^ bit2)
crc ^= 0x4CC5U;
}
return crc & 0x7FFFU;
}

View File

@ -1,42 +0,0 @@
/*
* Copyright (C) 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(NXDNCRC_H)
#define NXDNCRC_H
#include <cstdint>
class CNXDNCRC
{
public:
static bool checkCRC6(const unsigned char* in, unsigned int length);
static void encodeCRC6(unsigned char* in, unsigned int length);
static bool checkCRC12(const unsigned char* in, unsigned int length);
static void encodeCRC12(unsigned char* in, unsigned int length);
static bool checkCRC15(const unsigned char* in, unsigned int length);
static void encodeCRC15(unsigned char* in, unsigned int length);
private:
static uint8_t createCRC6(const unsigned char* in, unsigned int length);
static uint16_t createCRC12(const unsigned char* in, unsigned int length);
static uint16_t createCRC15(const unsigned char* in, unsigned int length);
};
#endif

View File

@ -1,160 +0,0 @@
/*
* Copyright (C) 2016,2017,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 "NXDNLookup.h"
#include "Timer.h"
#include "Log.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
CNXDNLookup::CNXDNLookup(const std::string& filename, unsigned int reloadTime) :
CThread(),
m_filename(filename),
m_reloadTime(reloadTime),
m_table(),
m_mutex(),
m_stop(false)
{
}
CNXDNLookup::~CNXDNLookup()
{
}
bool CNXDNLookup::read()
{
bool ret = load();
if (m_reloadTime > 0U)
run();
return ret;
}
void CNXDNLookup::entry()
{
LogInfo("Started the NXDN 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 NXDN Id lookup reload thread");
}
void CNXDNLookup::stop()
{
if (m_reloadTime == 0U) {
delete this;
return;
}
m_stop = true;
wait();
}
std::string CNXDNLookup::find(unsigned int id)
{
std::string callsign;
if (id == 0xFFFFU)
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 CNXDNLookup::exists(unsigned int id)
{
m_mutex.lock();
bool found = m_table.count(id) == 1U;
m_mutex.unlock();
return found;
}
bool CNXDNLookup::load()
{
FILE* fp = ::fopen(m_filename.c_str(), "rt");
if (fp == NULL) {
LogWarning("Cannot open the NXDN 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);
if (id > 0U) {
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 NXDN callsign lookup table", size);
return true;
}

View File

@ -1,53 +0,0 @@
/*
* Copyright (C) 2016,2017,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.
*/
#ifndef NXDNLookup_H
#define NXDNLookup_H
#include "Thread.h"
#include "Mutex.h"
#include <string>
#include <unordered_map>
class CNXDNLookup : public CThread {
public:
CNXDNLookup(const std::string& filename, unsigned int reloadTime);
virtual ~CNXDNLookup();
bool read();
virtual void entry();
std::string find(unsigned int id);
bool exists(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

View File

@ -1,126 +0,0 @@
/*
* Copyright (C) 2009-2014,2016,2018,2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "NXDNNetwork.h"
#include "Utils.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
CNXDNNetwork::CNXDNNetwork(unsigned short port, bool debug) :
m_socket(port),
m_debug(debug)
{
}
CNXDNNetwork::~CNXDNNetwork()
{
}
bool CNXDNNetwork::open()
{
LogInfo("Opening NXDN network connection");
return m_socket.open();
}
bool CNXDNNetwork::write(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, "NXDN Network Data Sent", data, length);
return m_socket.write(data, length, addr, addrLen);
}
bool CNXDNNetwork::write(const unsigned char* data, unsigned int length, unsigned short srcId, unsigned short dstId, bool grp, const sockaddr_storage& addr, unsigned int addrLen)
{
assert(data != NULL);
assert(length > 0U);
unsigned char buffer[50U];
buffer[0U] = 'N';
buffer[1U] = 'X';
buffer[2U] = 'D';
buffer[3U] = 'N';
buffer[4U] = 'D';
buffer[5U] = (srcId >> 8) & 0xFFU;
buffer[6U] = (srcId >> 0) & 0xFFU;
buffer[7U] = (dstId >> 8) & 0xFFU;
buffer[8U] = (dstId >> 0) & 0xFFU;
buffer[9U] = 0x00U;
buffer[9U] |= grp ? 0x01U : 0x00U;
if (data[0U] == 0x81U || data[0U] == 0x83U) {
// This is a voice header or trailer.
buffer[9U] |= data[5U] == 0x01U ? 0x04U : 0x00U;
buffer[9U] |= data[5U] == 0x08U ? 0x08U : 0x00U;
} else if ((data[0U] & 0xF0U) == 0x90U) {
// This if data.
buffer[9U] |= 0x02U;
if (data[0U] == 0x90U || data[0U] == 0x92U || data[0U] == 0x9CU || data[0U] == 0x9EU) {
// This is data header or trailer.
buffer[9U] |= data[2U] == 0x09U ? 0x04U : 0x00U;
buffer[9U] |= data[2U] == 0x08U ? 0x08U : 0x00U;
}
}
::memcpy(buffer + 10U, data, 33U);
if (m_debug)
CUtils::dump(1U, "NXDN Network Data Sent", buffer, 43U);
return m_socket.write(buffer, 43U, addr, addrLen);
}
unsigned int CNXDNNetwork::read(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;
// Invalid packet type?
if (::memcmp(data, "NXDN", 4U) != 0)
return 0U;
if (len != 17 && len != 43)
return 0U;
if (m_debug)
CUtils::dump(1U, "NXDN Network Data Received", data, len);
return len;
}
void CNXDNNetwork::close()
{
m_socket.close();
LogInfo("Closing NXDN network connection");
}

View File

@ -1,46 +0,0 @@
/*
* Copyright (C) 2009-2014,2016,2018,2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef NXDNNetwork_H
#define NXDNNetwork_H
#include "UDPSocket.h"
#include <cstdint>
#include <string>
class CNXDNNetwork {
public:
CNXDNNetwork(unsigned short port, bool debug);
~CNXDNNetwork();
bool open();
bool write(const unsigned char* data, unsigned int length, const sockaddr_storage& address, unsigned int addrLen);
bool write(const unsigned char* data, unsigned int length, unsigned short srcId, unsigned short dstId, bool grp, const sockaddr_storage& addr, unsigned int addrLen);
unsigned int read(unsigned char* data, unsigned int length, sockaddr_storage& addr, unsigned int& addrLen);
void close();
private:
CUDPSocket m_socket;
bool m_debug;
};
#endif

View File

@ -1,629 +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 "NXDNReflector.h"
#include "NXDNNetwork.h"
#include "NXDNLookup.h"
#include "StopWatch.h"
#include "Version.h"
#include "Thread.h"
#include "Utils.h"
#include "Log.h"
#if defined(_WIN32) || defined(_WIN64)
#include <Windows.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <pwd.h>
#endif
#if defined(_WIN32) || defined(_WIN64)
const char* DEFAULT_INI_FILE = "NXDNReflector.ini";
#else
const char* DEFAULT_INI_FILE = "/etc/NXDNReflector.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, "NXDNReflector version %s\n", VERSION);
return 0;
} else if (arg.substr(0, 1) == "-") {
::fprintf(stderr, "Usage: NXDNReflector [-v|--version] [filename]\n");
return 1;
} else {
iniFile = argv[currentArg];
}
}
}
CNXDNReflector* reflector = new CNXDNReflector(std::string(iniFile));
reflector->run();
delete reflector;
return 0;
}
CNXDNReflector::CNXDNReflector(const std::string& file) :
m_conf(file),
m_icomNetwork(NULL),
m_kenwoodNetwork(NULL),
m_repeaters()
{
CUDPSocket::startup();
}
CNXDNReflector::~CNXDNReflector()
{
CUDPSocket::shutdown();
}
void CNXDNReflector::run()
{
bool ret = m_conf.read();
if (!ret) {
::fprintf(stderr, "NXDNReflector: 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, "NXDNReflector: 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
unsigned short tg = m_conf.getTG();
CNXDNNetwork nxdnNetwork(m_conf.getNetworkPort(), m_conf.getNetworkDebug());
ret = nxdnNetwork.open();
if (!ret) {
::LogFinalise();
return;
}
bool icomEnabled = m_conf.getIcomEnabled();
unsigned short icomTGEnable = 0U;
unsigned short icomTGDisable = 0U;
if (icomEnabled) {
ret = openIcomNetwork();
if (!ret) {
nxdnNetwork.close();
::LogFinalise();
return;
}
icomTGEnable = m_conf.getIcomTGEnable();
icomTGDisable = m_conf.getIcomTGDisable();
}
bool kenwoodEnabled = m_conf.getKenwoodEnabled();
unsigned short kenwoodTGEnable = 0U;
unsigned short kenwoodTGDisable = 0U;
if (kenwoodEnabled) {
ret = openKenwoodNetwork();
if (!ret) {
nxdnNetwork.close();
::LogFinalise();
return;
}
kenwoodTGEnable = m_conf.getKenwoodTGEnable();
kenwoodTGDisable = m_conf.getKenwoodTGDisable();
}
CNXDNLookup* lookup = new CNXDNLookup(m_conf.getLookupName(), m_conf.getLookupTime());
lookup->read();
CStopWatch stopWatch;
stopWatch.start();
CTimer dumpTimer(1000U, 120U);
dumpTimer.start();
LogMessage("Starting NXDNReflector-%s", VERSION);
enum {
ACTIVE_NONE,
ACTIVE_NXDN,
ACTIVE_ICOM,
ACTIVE_KENWOOD
} active = ACTIVE_NONE;
CNXDNRepeater* current = NULL;
unsigned short srcId = 0U;
unsigned short dstId = 0U;
bool grp = false;
CTimer watchdogTimer(1000U, 0U, 1500U);
for (;;) {
unsigned char buffer[200U];
sockaddr_storage address;
unsigned int addressLen;
unsigned int len = nxdnNetwork.read(buffer, 200U, address, addressLen);
if (len > 0U) {
CNXDNRepeater* rpt = findRepeater(address);
if (::memcmp(buffer, "NXDNP", 5U) == 0 && len == 17U) {
unsigned short id = (buffer[15U] << 8) | buffer[16U];
if (id == tg) {
if (rpt == NULL) {
rpt = new CNXDNRepeater;
rpt->m_timer.start();
::memcpy(&rpt->m_addr, &address, sizeof(struct sockaddr_storage));
rpt->m_addrLen = addressLen;
rpt->m_callsign = std::string((char*)(buffer + 5U), 10U);
m_repeaters.push_back(rpt);
char buff[80U];
LogMessage("Adding %s (%s)", rpt->m_callsign.c_str(), CUDPSocket::display(address, buff, 80U));
} else {
rpt->m_timer.start();
}
// Return the poll
nxdnNetwork.write(buffer, len, address, addressLen);
}
} else if (::memcmp(buffer, "NXDNU", 5U) == 0 && len == 17U) {
unsigned short id = (buffer[15U] << 8) | buffer[16U];
if (id == tg) {
if (rpt != NULL) {
std::string callsign = std::string((char*)(buffer + 5U), 10U);
char buff[80U];
LogMessage("Removing %s (%s) unlinked", callsign.c_str(), CUDPSocket::display(address, buff, 80U));
for (std::vector<CNXDNRepeater*>::iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
if (*it == rpt) {
m_repeaters.erase(it);
break;
}
}
delete rpt;
}
}
} else if (::memcmp(buffer, "NXDND", 5U) == 0 && len == 43U) {
if (rpt != NULL) {
unsigned short srcId = (buffer[5U] << 8) | buffer[6U];
unsigned short dstId = (buffer[7U] << 8) | buffer[8U];
bool grp = (buffer[9U] & 0x01U) == 0x01U;
if (icomEnabled && icomTGEnable != 0U && grp && dstId == icomTGEnable) {
if (m_icomNetwork == NULL) {
std::string callsign = lookup->find(srcId);
LogMessage("Icom Network link enabled by %s at %s", callsign.c_str(), current->m_callsign.c_str());
bool ok = openIcomNetwork();
if (!ok)
LogWarning("Unable to open the Icom Network link");
}
}
if (kenwoodEnabled && kenwoodTGEnable != 0U && grp && dstId == kenwoodTGEnable) {
if (m_kenwoodNetwork == NULL) {
std::string callsign = lookup->find(srcId);
LogMessage("Kenwood Network link enabled by %s at %s", callsign.c_str(), current->m_callsign.c_str());
bool ok = openKenwoodNetwork();
if (!ok)
LogWarning("Unable to open the Kenwood Network link");
}
}
if (icomEnabled && icomTGDisable != 0U && grp && dstId == icomTGDisable) {
if (m_icomNetwork != NULL) {
std::string callsign = lookup->find(srcId);
LogMessage("Icom Network link disabled by %s at %s", callsign.c_str(), current->m_callsign.c_str());
closeIcomNetwork();
}
}
if (kenwoodEnabled && kenwoodTGDisable != 0U && grp && dstId == kenwoodTGDisable) {
if (m_kenwoodNetwork != NULL) {
std::string callsign = lookup->find(srcId);
LogMessage("Kenwood Network link disabled by %s at %s", callsign.c_str(), current->m_callsign.c_str());
closeKenwoodNetwork();
}
}
if (grp && dstId == tg) {
rpt->m_timer.start();
if (current == NULL && active == ACTIVE_NONE) {
current = rpt;
std::string callsign = lookup->find(srcId);
LogMessage("Transmission from %s at %s to %s%u", callsign.c_str(), current->m_callsign.c_str(), grp ? "TG " : "", dstId);
active = ACTIVE_NXDN;
}
if (active == ACTIVE_NXDN) {
watchdogTimer.start();
for (std::vector<CNXDNRepeater*>::const_iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
if (!CUDPSocket::match((*it)->m_addr, address))
nxdnNetwork.write(buffer, len, (*it)->m_addr, (*it)->m_addrLen);
}
if (m_icomNetwork != NULL)
m_icomNetwork->write(buffer, len);
if (m_kenwoodNetwork != NULL)
m_kenwoodNetwork->write(buffer, len);
if ((buffer[9U] & 0x08U) == 0x08U) {
LogMessage("Received end of transmission");
current = NULL;
active = ACTIVE_NONE;
watchdogTimer.stop();
}
}
}
} else {
LogMessage("Data received from an unknown source");
CUtils::dump(2U, "Data", buffer, len);
}
}
}
if (m_icomNetwork != NULL) {
len = m_icomNetwork->read(buffer);
if (len > 0U) {
if (current == NULL) {
if (active == ACTIVE_NONE) {
if ((buffer[0U] == 0x81U || buffer[0U] == 0x83U) && buffer[5U] == 0x01U) {
bool tempGrp = (buffer[7U] & 0x20U) == 0x20U;
unsigned short tempSrcId = (buffer[8U] << 8) | buffer[9U];
unsigned short tempDstId = (buffer[10U] << 8) | buffer[11U];
if (tempGrp && tempDstId == tg) {
// Save the grp, src and dest for use in the NXDN Protocol messages
grp = tempGrp;
srcId = tempSrcId;
dstId = tempDstId;
std::string callsign = lookup->find(srcId);
LogMessage("Transmission from %s on Icom Network to %s%u", callsign.c_str(), grp ? "TG " : "", dstId);
active = ACTIVE_ICOM;
}
}
if ((buffer[0U] & 0xF0U) == 0x90U && buffer[2U] == 0x09U) {
bool tempGrp = (buffer[4U] & 0x20U) == 0x20U;
unsigned short tempSrcId = (buffer[5U] << 8) | buffer[6U];
unsigned short tempDstId = (buffer[7U] << 8) | buffer[8U];
if (tempGrp && tempDstId == tg) {
// Save the grp, src and dest for use in the NXDN Protocol messages
grp = tempGrp;
srcId = tempSrcId;
dstId = tempDstId;
std::string callsign = lookup->find(srcId);
LogMessage("Transmission from %s on Icom Network to %s%u", callsign.c_str(), grp ? "TG " : "", dstId);
active = ACTIVE_ICOM;
}
}
}
if (active == ACTIVE_ICOM) {
watchdogTimer.start();
for (std::vector<CNXDNRepeater*>::const_iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it)
nxdnNetwork.write(buffer, len, srcId, dstId, grp, (*it)->m_addr, (*it)->m_addrLen);
if (m_kenwoodNetwork != NULL)
m_kenwoodNetwork->write(buffer, len);
if ((buffer[0U] == 0x81U || buffer[0U] == 0x83U) && buffer[5U] == 0x08U) {
LogMessage("Received end of transmission");
active = ACTIVE_NONE;
watchdogTimer.stop();
}
if ((buffer[0U] & 0xF0U) == 0x90U && buffer[2U] == 0x08U) {
LogMessage("Received end of transmission");
active = ACTIVE_NONE;
watchdogTimer.stop();
}
}
}
}
}
if (m_kenwoodNetwork != NULL) {
len = m_kenwoodNetwork->read(buffer);
if (len > 0U) {
if (current == NULL) {
if (active == ACTIVE_NONE) {
if ((buffer[0U] == 0x81U || buffer[0U] == 0x83U) && buffer[5U] == 0x01U) {
bool tempGrp = (buffer[7U] & 0x20U) == 0x20U;
unsigned short tempSrcId = (buffer[8U] << 8) | buffer[9U];
unsigned short tempDstId = (buffer[10U] << 8) | buffer[11U];
if (tempGrp && tempDstId == tg) {
// Save the grp, src and dest for use in the NXDN Protocol messages
grp = tempGrp;
srcId = tempSrcId;
dstId = tempDstId;
std::string callsign = lookup->find(srcId);
LogMessage("Transmission from %s on Kenwood Network to %s%u", callsign.c_str(), grp ? "TG " : "", dstId);
active = ACTIVE_KENWOOD;
}
}
if ((buffer[0U] & 0xF0U) == 0x90U && buffer[2U] == 0x09U) {
bool tempGrp = (buffer[4U] & 0x20U) == 0x20U;
unsigned short tempSrcId = (buffer[5U] << 8) | buffer[6U];
unsigned short tempDstId = (buffer[7U] << 8) | buffer[8U];
if (tempGrp && tempDstId == tg) {
// Save the grp, src and dest for use in the NXDN Protocol messages
grp = tempGrp;
srcId = tempSrcId;
dstId = tempDstId;
std::string callsign = lookup->find(srcId);
LogMessage("Transmission from %s on Kenwood Network to %s%u", callsign.c_str(), grp ? "TG " : "", dstId);
active = ACTIVE_KENWOOD;
}
}
}
if (active == ACTIVE_KENWOOD) {
watchdogTimer.start();
for (std::vector<CNXDNRepeater*>::const_iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it)
nxdnNetwork.write(buffer, len, srcId, dstId, grp, (*it)->m_addr, (*it)->m_addrLen);
if (m_icomNetwork != NULL)
m_icomNetwork->write(buffer, len);
if ((buffer[0U] == 0x81U || buffer[0U] == 0x83U) && buffer[5U] == 0x08U) {
LogMessage("Received end of transmission");
active = ACTIVE_NONE;
watchdogTimer.stop();
}
if ((buffer[0U] & 0xF0U) == 0x90U && buffer[2U] == 0x08U) {
LogMessage("Received end of transmission");
active = ACTIVE_NONE;
watchdogTimer.stop();
}
}
}
}
}
unsigned int ms = stopWatch.elapsed();
stopWatch.start();
// Remove any repeaters that haven't reported for a while
for (std::vector<CNXDNRepeater*>::iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it)
(*it)->m_timer.clock(ms);
for (std::vector<CNXDNRepeater*>::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;
active = ACTIVE_NONE;
}
dumpTimer.clock(ms);
if (dumpTimer.hasExpired()) {
dumpRepeaters();
dumpTimer.start();
}
if (m_icomNetwork != NULL)
m_icomNetwork->clock(ms);
if (m_kenwoodNetwork != NULL)
m_kenwoodNetwork->clock(ms);
if (ms < 5U)
CThread::sleep(5U);
}
nxdnNetwork.close();
closeIcomNetwork();
closeKenwoodNetwork();
lookup->stop();
::LogFinalise();
}
CNXDNRepeater* CNXDNReflector::findRepeater(const sockaddr_storage& addr) const
{
for (std::vector<CNXDNRepeater*>::const_iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
if (CUDPSocket::match(addr, (*it)->m_addr))
return *it;
}
return NULL;
}
void CNXDNReflector::dumpRepeaters() const
{
if (m_repeaters.size() == 0U) {
LogMessage("No repeaters linked");
return;
}
LogMessage("Currently linked repeaters:");
for (std::vector<CNXDNRepeater*>::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());
}
}
bool CNXDNReflector::openIcomNetwork()
{
m_icomNetwork = new CIcomNetwork(m_conf.getIcomAddress(), m_conf.getIcomDebug());
bool ret = m_icomNetwork->open();
if (!ret) {
delete m_icomNetwork;
m_icomNetwork = NULL;
return false;
}
return true;
}
bool CNXDNReflector::openKenwoodNetwork()
{
m_kenwoodNetwork = new CKenwoodNetwork(m_conf.getKenwoodAddress(), m_conf.getKenwoodDebug());
bool ret = m_kenwoodNetwork->open();
if (!ret) {
delete m_kenwoodNetwork;
m_kenwoodNetwork = NULL;
return false;
}
return true;
}
void CNXDNReflector::closeIcomNetwork()
{
if (m_icomNetwork != NULL) {
m_icomNetwork->close();
delete m_icomNetwork;
m_icomNetwork = NULL;
}
}
void CNXDNReflector::closeKenwoodNetwork()
{
if (m_kenwoodNetwork != NULL) {
m_kenwoodNetwork->close();
delete m_kenwoodNetwork;
m_kenwoodNetwork = NULL;
}
}

View File

@ -1,82 +0,0 @@
/*
* Copyright (C) 2016,2018,2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(NXDNReflector_H)
#define NXDNReflector_H
#include "KenwoodNetwork.h"
#include "IcomNetwork.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 <winsock.h>
#endif
class CNXDNRepeater {
public:
CNXDNRepeater() :
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 CNXDNReflector
{
public:
CNXDNReflector(const std::string& file);
~CNXDNReflector();
void run();
private:
CConf m_conf;
CIcomNetwork* m_icomNetwork;
CKenwoodNetwork* m_kenwoodNetwork;
std::vector<CNXDNRepeater*> m_repeaters;
CNXDNRepeater* findRepeater(const sockaddr_storage& addr) const;
void dumpRepeaters() const;
bool openIcomNetwork();
bool openKenwoodNetwork();
void closeIcomNetwork();
void closeKenwoodNetwork();
};
#endif

View File

@ -1,35 +0,0 @@
[General]
TG=9999
Daemon=1
[Id Lookup]
Name=NXDN.csv
Time=24
[Log]
# Logging levels, 0=No logging
DisplayLevel=1
FileLevel=1
FilePath=.
FileRoot=NXDNReflector
FileRotate=1
[Network]
Port=41400
Debug=0
# Please visit www.nxdninfo.com if you are planning to link to the Icom NXCore server in Florida.
[Icom Network]
Enabled=0
Address=flicom.nxcore.org
# TGEnable=1234
# TGDisable=3456
Debug=0
# Note that the Kenwood NXCore server in Florida is offline.
[Kenwood Network]
Enabled=0
Address=flkenwood.nxcore.org
# TGEnable=1234
# TGDisable=3456
Debug=0

View File

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

View File

@ -1,31 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2026
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NXDNReflector", "NXDNReflector.vcxproj", "{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{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
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {32F19C39-C6E7-44AB-BE4C-EA8DD3C57231}
EndGlobalSection
EndGlobal

View File

@ -1,189 +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="IcomNetwork.h" />
<ClInclude Include="KenwoodNetwork.h" />
<ClInclude Include="NXDNCRC.h" />
<ClInclude Include="NXDNLookup.h" />
<ClInclude Include="Log.h" />
<ClInclude Include="Mutex.h" />
<ClInclude Include="NXDNNetwork.h" />
<ClInclude Include="NXDNReflector.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="IcomNetwork.cpp" />
<ClCompile Include="KenwoodNetwork.cpp" />
<ClCompile Include="NXDNCRC.cpp" />
<ClCompile Include="NXDNLookup.cpp" />
<ClCompile Include="Log.cpp" />
<ClCompile Include="Mutex.cpp" />
<ClCompile Include="NXDNNetwork.cpp" />
<ClCompile Include="NXDNReflector.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>NXDNReflector</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>

View File

@ -1,104 +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="NXDNLookup.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="NXDNReflector.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>
<ClInclude Include="NXDNNetwork.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="IcomNetwork.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="KenwoodNetwork.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NXDNCRC.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Conf.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NXDNLookup.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="NXDNReflector.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>
<ClCompile Include="NXDNNetwork.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="IcomNetwork.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="KenwoodNetwork.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NXDNCRC.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -1,105 +0,0 @@
/*
* Copyright (C) 2015,2016,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "StopWatch.h"
#if defined(_WIN32) || defined(_WIN64)
CStopWatch::CStopWatch() :
m_frequencyS(),
m_frequencyMS(),
m_start()
{
::QueryPerformanceFrequency(&m_frequencyS);
m_frequencyMS.QuadPart = m_frequencyS.QuadPart / 1000ULL;
}
CStopWatch::~CStopWatch()
{
}
unsigned long long CStopWatch::time() const
{
LARGE_INTEGER now;
::QueryPerformanceCounter(&now);
return (unsigned long long)(now.QuadPart / m_frequencyMS.QuadPart);
}
unsigned long long CStopWatch::start()
{
::QueryPerformanceCounter(&m_start);
return (unsigned long long)(m_start.QuadPart / m_frequencyS.QuadPart);
}
unsigned int CStopWatch::elapsed()
{
LARGE_INTEGER now;
::QueryPerformanceCounter(&now);
LARGE_INTEGER temp;
temp.QuadPart = (now.QuadPart - m_start.QuadPart) * 1000;
return (unsigned int)(temp.QuadPart / m_frequencyS.QuadPart);
}
#else
#include <cstdio>
#include <ctime>
CStopWatch::CStopWatch() :
m_startMS(0ULL)
{
}
CStopWatch::~CStopWatch()
{
}
unsigned long long CStopWatch::time() const
{
struct timeval now;
::gettimeofday(&now, NULL);
return now.tv_sec * 1000ULL + now.tv_usec / 1000ULL;
}
unsigned long long CStopWatch::start()
{
struct timespec now;
::clock_gettime(CLOCK_MONOTONIC, &now);
m_startMS = now.tv_sec * 1000ULL + now.tv_nsec / 1000000ULL;
return m_startMS;
}
unsigned int CStopWatch::elapsed()
{
struct timespec now;
::clock_gettime(CLOCK_MONOTONIC, &now);
unsigned long long nowMS = now.tv_sec * 1000ULL + now.tv_nsec / 1000000ULL;
return nowMS - m_startMS;
}
#endif

View File

@ -1,50 +0,0 @@
/*
* Copyright (C) 2015,2016,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(STOPWATCH_H)
#define STOPWATCH_H
#if defined(_WIN32) || defined(_WIN64)
#include <WS2tcpip.h>
#include <windows.h>
#else
#include <sys/time.h>
#endif
class CStopWatch
{
public:
CStopWatch();
~CStopWatch();
unsigned long long time() const;
unsigned long long start();
unsigned int elapsed();
private:
#if defined(_WIN32) || defined(_WIN64)
LARGE_INTEGER m_frequencyS;
LARGE_INTEGER m_frequencyMS;
LARGE_INTEGER m_start;
#else
unsigned long long m_startMS;
#endif
};
#endif

View File

@ -1,107 +0,0 @@
/*
* Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Thread.h"
#if defined(_WIN32) || defined(_WIN64)
CThread::CThread() :
m_handle()
{
}
CThread::~CThread()
{
}
bool CThread::run()
{
m_handle = ::CreateThread(NULL, 0, &helper, this, 0, NULL);
return m_handle != NULL;
}
void CThread::wait()
{
::WaitForSingleObject(m_handle, INFINITE);
::CloseHandle(m_handle);
}
DWORD CThread::helper(LPVOID arg)
{
CThread* p = (CThread*)arg;
p->entry();
return 0UL;
}
void CThread::sleep(unsigned int ms)
{
::Sleep(ms);
}
#else
#include <unistd.h>
CThread::CThread() :
m_thread()
{
}
CThread::~CThread()
{
}
bool CThread::run()
{
return ::pthread_create(&m_thread, NULL, helper, this) == 0;
}
void CThread::wait()
{
::pthread_join(m_thread, NULL);
}
void* CThread::helper(void* arg)
{
CThread* p = (CThread*)arg;
p->entry();
return NULL;
}
void CThread::sleep(unsigned int ms)
{
struct timespec ts;
ts.tv_sec = ms / 1000U;
ts.tv_nsec = (ms % 1000U) * 1000000U;
::nanosleep(&ts, NULL);
}
#endif

View File

@ -1,56 +0,0 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(THREAD_H)
#define THREAD_H
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#else
#include <pthread.h>
#endif
class CThread
{
public:
CThread();
virtual ~CThread();
virtual bool run();
virtual void entry() = 0;
virtual void wait();
static void sleep(unsigned int ms);
private:
#if defined(_WIN32) || defined(_WIN64)
HANDLE m_handle;
#else
pthread_t m_thread;
#endif
#if defined(_WIN32) || defined(_WIN64)
static DWORD __stdcall helper(LPVOID arg);
#else
static void* helper(void* arg);
#endif
};
#endif

View File

@ -1,68 +0,0 @@
/*
* Copyright (C) 2009,2010,2015 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Timer.h"
#include <cstdio>
#include <cassert>
CTimer::CTimer(unsigned int ticksPerSec, unsigned int secs, unsigned int msecs) :
m_ticksPerSec(ticksPerSec),
m_timeout(0U),
m_timer(0U)
{
assert(ticksPerSec > 0U);
if (secs > 0U || msecs > 0U) {
// m_timeout = ((secs * 1000U + msecs) * m_ticksPerSec) / 1000U + 1U;
unsigned long long temp = (secs * 1000ULL + msecs) * m_ticksPerSec;
m_timeout = (unsigned int)(temp / 1000ULL + 1ULL);
}
}
CTimer::~CTimer()
{
}
void CTimer::setTimeout(unsigned int secs, unsigned int msecs)
{
if (secs > 0U || msecs > 0U) {
// m_timeout = ((secs * 1000U + msecs) * m_ticksPerSec) / 1000U + 1U;
unsigned long long temp = (secs * 1000ULL + msecs) * m_ticksPerSec;
m_timeout = (unsigned int)(temp / 1000ULL + 1ULL);
} else {
m_timeout = 0U;
m_timer = 0U;
}
}
unsigned int CTimer::getTimeout() const
{
if (m_timeout == 0U)
return 0U;
return (m_timeout - 1U) / m_ticksPerSec;
}
unsigned int CTimer::getTimer() const
{
if (m_timer == 0U)
return 0U;
return (m_timer - 1U) / m_ticksPerSec;
}

View File

@ -1,89 +0,0 @@
/*
* Copyright (C) 2009,2010,2011,2014 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef Timer_H
#define Timer_H
class CTimer {
public:
CTimer(unsigned int ticksPerSec, unsigned int secs = 0U, unsigned int msecs = 0U);
~CTimer();
void setTimeout(unsigned int secs, unsigned int msecs = 0U);
unsigned int getTimeout() const;
unsigned int getTimer() const;
unsigned int getRemaining()
{
if (m_timeout == 0U || m_timer == 0U)
return 0U;
if (m_timer >= m_timeout)
return 0U;
return (m_timeout - m_timer) / m_ticksPerSec;
}
bool isRunning()
{
return m_timer > 0U;
}
void start(unsigned int secs, unsigned int msecs = 0U)
{
setTimeout(secs, msecs);
start();
}
void start()
{
if (m_timeout > 0U)
m_timer = 1U;
}
void stop()
{
m_timer = 0U;
}
bool hasExpired()
{
if (m_timeout == 0U || m_timer == 0U)
return false;
if (m_timer >= m_timeout)
return true;
return false;
}
void clock(unsigned int ticks = 1U)
{
if (m_timer > 0U && m_timeout > 0U)
m_timer += ticks;
}
private:
unsigned int m_ticksPerSec;
unsigned int m_timeout;
unsigned int m_timer;
};
#endif

View File

@ -1,391 +0,0 @@
/*
* Copyright (C) 2006-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.
*/
#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;
}
}

View File

@ -1,85 +0,0 @@
/*
* Copyright (C) 2009-2011,2013,2015,2016,2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef UDPSocket_H
#define UDPSocket_H
#include <string>
#if !defined(_WIN32) && !defined(_WIN64)
#include <netdb.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <poll.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#else
#include <ws2tcpip.h>
#endif
#if !defined(UDP_SOCKET_MAX)
#define UDP_SOCKET_MAX 1
#endif
enum IPMATCHTYPE {
IMT_ADDRESS_AND_PORT,
IMT_ADDRESS_ONLY
};
class CUDPSocket {
public:
CUDPSocket(const std::string& address, unsigned 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

View File

@ -1,146 +0,0 @@
/*
* Copyright (C) 2009,2014,2015,2016 Jonathan Naylor, G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "Utils.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
void CUtils::dump(const std::string& title, const unsigned char* data, unsigned int length)
{
assert(data != NULL);
dump(2U, title, data, length);
}
void CUtils::dump(int level, const std::string& title, const unsigned char* data, unsigned int length)
{
assert(data != NULL);
::Log(level, "%s", title.c_str());
unsigned int offset = 0U;
while (length > 0U) {
std::string output;
unsigned int bytes = (length > 16U) ? 16U : length;
for (unsigned i = 0U; i < bytes; i++) {
char temp[10U];
::sprintf(temp, "%02X ", data[offset + i]);
output += temp;
}
for (unsigned int i = bytes; i < 16U; i++)
output += " ";
output += " *";
for (unsigned i = 0U; i < bytes; i++) {
unsigned char c = data[offset + i];
if (::isprint(c))
output += c;
else
output += '.';
}
output += '*';
::Log(level, "%04X: %s", offset, output.c_str());
offset += 16U;
if (length >= 16U)
length -= 16U;
else
length = 0U;
}
}
void CUtils::dump(const std::string& title, const bool* bits, unsigned int length)
{
assert(bits != NULL);
dump(2U, title, bits, length);
}
void CUtils::dump(int level, const std::string& title, const bool* bits, unsigned int length)
{
assert(bits != NULL);
unsigned char bytes[100U];
unsigned int nBytes = 0U;
for (unsigned int n = 0U; n < length; n += 8U, nBytes++)
bitsToByteBE(bits + n, bytes[nBytes]);
dump(level, title, bytes, nBytes);
}
void CUtils::byteToBitsBE(unsigned char byte, bool* bits)
{
assert(bits != NULL);
bits[0U] = (byte & 0x80U) == 0x80U;
bits[1U] = (byte & 0x40U) == 0x40U;
bits[2U] = (byte & 0x20U) == 0x20U;
bits[3U] = (byte & 0x10U) == 0x10U;
bits[4U] = (byte & 0x08U) == 0x08U;
bits[5U] = (byte & 0x04U) == 0x04U;
bits[6U] = (byte & 0x02U) == 0x02U;
bits[7U] = (byte & 0x01U) == 0x01U;
}
void CUtils::byteToBitsLE(unsigned char byte, bool* bits)
{
assert(bits != NULL);
bits[0U] = (byte & 0x01U) == 0x01U;
bits[1U] = (byte & 0x02U) == 0x02U;
bits[2U] = (byte & 0x04U) == 0x04U;
bits[3U] = (byte & 0x08U) == 0x08U;
bits[4U] = (byte & 0x10U) == 0x10U;
bits[5U] = (byte & 0x20U) == 0x20U;
bits[6U] = (byte & 0x40U) == 0x40U;
bits[7U] = (byte & 0x80U) == 0x80U;
}
void CUtils::bitsToByteBE(const bool* bits, unsigned char& byte)
{
assert(bits != NULL);
byte = bits[0U] ? 0x80U : 0x00U;
byte |= bits[1U] ? 0x40U : 0x00U;
byte |= bits[2U] ? 0x20U : 0x00U;
byte |= bits[3U] ? 0x10U : 0x00U;
byte |= bits[4U] ? 0x08U : 0x00U;
byte |= bits[5U] ? 0x04U : 0x00U;
byte |= bits[6U] ? 0x02U : 0x00U;
byte |= bits[7U] ? 0x01U : 0x00U;
}
void CUtils::bitsToByteLE(const bool* bits, unsigned char& byte)
{
assert(bits != NULL);
byte = bits[0U] ? 0x01U : 0x00U;
byte |= bits[1U] ? 0x02U : 0x00U;
byte |= bits[2U] ? 0x04U : 0x00U;
byte |= bits[3U] ? 0x08U : 0x00U;
byte |= bits[4U] ? 0x10U : 0x00U;
byte |= bits[5U] ? 0x20U : 0x00U;
byte |= bits[6U] ? 0x40U : 0x00U;
byte |= bits[7U] ? 0x80U : 0x00U;
}

View File

@ -1,36 +0,0 @@
/*
* Copyright (C) 2009,2014,2015 by Jonathan Naylor, G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef Utils_H
#define Utils_H
#include <string>
class CUtils {
public:
static void dump(const std::string& title, const unsigned char* data, unsigned int length);
static void dump(int level, const std::string& title, const unsigned char* data, unsigned int length);
static void dump(const std::string& title, const bool* bits, unsigned int length);
static void dump(int level, const std::string& title, const bool* bits, unsigned int length);
static void byteToBitsBE(unsigned char byte, bool* bits);
static void byteToBitsLE(unsigned char byte, bool* bits);
static void bitsToByteBE(const bool* bits, unsigned char& byte);
static void bitsToByteLE(const bool* bits, unsigned char& byte);
private:
};
#endif

View File

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

View File

@ -3,11 +3,6 @@ These programs are clients for the NXDN networking built into the MMDVM Host.
The Parrot is very simple minded and can only handle one client at a time and
is therefore not suitable for use as a shared resource via the Internet.
The Reflector is used as a single talk group in the same way that it is with
P25. It also includes the option to link it to NXCore to allow for interchange
of audio between the two. At the NXCore end, it should be set up to receive the
traffic from only one talk group.
The Gateway allows for use of NXDN Talk Groups to control the access to the
various NXDN reflectors. It speaks the same language as Icom repeaters to the
MMDVM so can be used as a gateway for Icom NXDN repeaters. It also