mirror of
https://github.com/nostar/urfd.git
synced 2026-11-08 04:19:39 +00:00
Merge pull request #1 from n7tae/main
run-time config nlohmann's json lib, codecstream improvements, readme rework
This commit is contained in:
155 files changed
+3037
-11086
No files matched your search
+3
-9
@@ -1,13 +1,7 @@
|
||||
*.o
|
||||
*.d
|
||||
.vscode
|
||||
reflector/urfd.blacklist
|
||||
reflector/urfd.whitelist
|
||||
reflector/urfd.interlink
|
||||
reflector/urfd.terminal
|
||||
configure.mk
|
||||
configure.h
|
||||
configure.sql
|
||||
reflector.cfg
|
||||
wiresx/configure.php
|
||||
reflector/urfd.*
|
||||
urfd
|
||||
inicheck
|
||||
dbutil
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
###### URFD CONFIGURATION Example ######
|
||||
# comments begin with '#'
|
||||
# Do not use quotes, unless in a comment!
|
||||
|
||||
[Names]
|
||||
Callsign = URF??? # where ? is A-Z or 0-9
|
||||
|
||||
SysopEmail = me@somewhere.com
|
||||
|
||||
# 2-letter country codes are listed at https://www.iban.com/country-codes
|
||||
Country = GB
|
||||
|
||||
Sponsor = My Home Club
|
||||
|
||||
[IP Addresses]
|
||||
# Binding addresses are usually the 'any' address
|
||||
IPv4Binding = 0.0.0.0
|
||||
|
||||
# define IPv6 if you want a "dual-stack" reflector
|
||||
# IPv6Binding = ::
|
||||
|
||||
# define if you want to override what urfd finds using ipv4.icanhazip.com
|
||||
# IPv4External = 4.3.2.1
|
||||
|
||||
# define if you want to override what urfd finds using ipv6.icanhazip.com
|
||||
# IPv6External = f:e:d:c:b:a:9:0
|
||||
|
||||
Transcoder = local # SORRY, but only local TC's are supported right now!
|
||||
|
||||
[Modules]
|
||||
# Modules = ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
Modules = ADMSZ
|
||||
Transcoded = A # comment out if you don't have transcoding hardware
|
||||
# Create Descriptions as needed...
|
||||
DescriptionA = Transcoded
|
||||
DescriptionD = DMR Chat
|
||||
DescriptionM = M17 Chat
|
||||
DescriptionS = DStar Chat
|
||||
DescriptionZ = Temp Meeting
|
||||
|
||||
# Protocols
|
||||
[Brandmeister]
|
||||
Enable = false # Set to true if you've configured BM connections in your urfd.interlink file.
|
||||
Port = 10002
|
||||
|
||||
[DCS]
|
||||
Port = 30051
|
||||
|
||||
[DExtra]
|
||||
Port = 30001
|
||||
|
||||
[DPlus]
|
||||
Port = 20001
|
||||
|
||||
[G3]
|
||||
Enable = true
|
||||
|
||||
[DMRPlus]
|
||||
Port = 8880
|
||||
|
||||
[M17]
|
||||
Port = 17000
|
||||
|
||||
[MMDVM]
|
||||
Port = 62030
|
||||
DefaultId = 0
|
||||
|
||||
[NXDN]
|
||||
Port = 41400
|
||||
AutoLinkModule = A # comment out if you want to disable AL
|
||||
ReflectorID = 12345
|
||||
|
||||
[P25]
|
||||
Port = 41000
|
||||
AutoLinkModule = A # comment out if you want to disable AL
|
||||
ReflectorID = 12345
|
||||
|
||||
[URF]
|
||||
Port = 10017
|
||||
|
||||
[USRP]
|
||||
Enable = false
|
||||
Callsign = ALLSTAR # set to NONE if you don't want to create this client
|
||||
IPAddress = 1.2.3.4 # the IP address of the USRP client (the Allstar node)
|
||||
RxPort = 34000
|
||||
TxPort = 32000
|
||||
Module = A # this has to be a transcoded module!
|
||||
#FilePath = /home/usr/clients.txt # a list of listen-only clients
|
||||
|
||||
[YSF]
|
||||
Port = 42000
|
||||
AutoLinkModule = A # comment out if you want to disable AL
|
||||
DefaultTxFreq = 446500000
|
||||
DefaultRxFreq = 446500000
|
||||
# if you've registered your reflector at register.ysfreflector.de:
|
||||
RegistrationID = 12345
|
||||
RegistrationName = US URF???
|
||||
RegistrationDescription = URF Reflector
|
||||
|
||||
######## Database files
|
||||
[DMR ID DB]
|
||||
Mode = http #### Mode is "http", "file", or "both"
|
||||
#### if "both", the url will be read first
|
||||
FilePath = /home/user/dmrid.dat # for you to add your own values
|
||||
# will be reloaded within 10s
|
||||
URL = http://xlxapi.rlx.lu/api/exportdmr.php # if Mode "http" or "both"
|
||||
RefreshMin = 179
|
||||
|
||||
[NXDN ID DB]
|
||||
Mode = http
|
||||
FilePath = /home/user/nxdn.dat
|
||||
URL = https://radioid.net/static/nxdn.csv
|
||||
RefreshMin = 1440 # radioid.net says this file is updated once/day
|
||||
|
||||
[YSF TX/RX DB]
|
||||
Mode = http
|
||||
FilePath = /home/user/ysfnode.dat
|
||||
URL = http://xlxapi.rlx.lu/api/exportysfrepeaters.php
|
||||
RefreshMin = 191
|
||||
|
||||
######### Other File locations
|
||||
[Files]
|
||||
PidPath = /var/run/xlxd.pid
|
||||
XmlPath = /var/log/xlxd.xml
|
||||
#JsonPath = /var/tmp/urfd.json # for future development
|
||||
WhitelistPath = /home/user/urfd.whitelist
|
||||
BlacklistPath = /home/user/urfd.blacklist
|
||||
InterlinkPath = /home/user/urfd.interlink
|
||||
G3TerminalPath = /home/user/urfd.terminal
|
||||
@@ -5,12 +5,10 @@
|
||||
# each entry specifies a remote XLX or XRF to peer with
|
||||
# format:
|
||||
# <URF callsign> <ip> <list of modules shared>
|
||||
# <XRF callsign> <ip> <local module><remote module>
|
||||
# example:
|
||||
# URF270 158.64.26.132 ACD
|
||||
# XRF270 158.64.26.132 BB
|
||||
#
|
||||
# note: the remote XLX must list this XLX in its interlink file
|
||||
# note: the remote URFD must list this in its interlink file
|
||||
# for the link to be established
|
||||
#
|
||||
#############################################################################
|
||||
@@ -0,0 +1,6 @@
|
||||
# this is where the binary will be installed
|
||||
BINDIR = /usr/local/bin
|
||||
|
||||
# besides making an executable that gdb can use,
|
||||
# this will also provide some additional log messsage
|
||||
debug = false
|
||||
@@ -5,7 +5,7 @@ After=systemd-user-session.service network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/local/bin/urfd
|
||||
ExecStart=/usr/local/bin/urfd /PATH_TO_INI_FILE
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
@@ -50,35 +50,13 @@ InstallReflector () {
|
||||
if [ ! -e urfd.interlink ]; then
|
||||
cp ../config/urfd.interlink .
|
||||
fi
|
||||
if [[ "$g3support" == true ]] && [ ! -e urfd.terminal ]; then
|
||||
if [ ! -e urfd.terminal ]; then
|
||||
cp ../config/urfd.terminal .
|
||||
fi
|
||||
sudo make install || read -p "<Enter> to continue: " ans
|
||||
popd
|
||||
}
|
||||
|
||||
Clean () {
|
||||
pushd reflector
|
||||
make clean
|
||||
popd
|
||||
pushd ../tcd
|
||||
make clean
|
||||
popd
|
||||
}
|
||||
|
||||
Compile () {
|
||||
local np
|
||||
np=`getconf _NPROCESSORS_ONLN`
|
||||
pushd reflector
|
||||
make -j$np || read -p "<Enter to continue: " ans
|
||||
popd
|
||||
if [[ "$tcaddress" != none ]]; then
|
||||
pushd ../tcd
|
||||
make -j$np || read -p "<Enter to continue: " ans
|
||||
popd
|
||||
fi
|
||||
}
|
||||
|
||||
# Execution starts here!
|
||||
|
||||
# service file locations
|
||||
@@ -87,13 +65,25 @@ tcdserv='/etc/systemd/system/tcd.service'
|
||||
|
||||
# default values, we only need a few
|
||||
tcaddress='none'
|
||||
g3support=false
|
||||
|
||||
if [ -e reflector.cfg ]; then
|
||||
source reflector.cfg
|
||||
if [[ $# -eq 1 ]]; then
|
||||
if [ -e $1 ]; then
|
||||
echo $1 found
|
||||
callsign=$(awk '$1 == "Callsign"{print $3}' $1)
|
||||
tcaddress=$(awk '$1 == "Transcoder"{print $3}' $1)
|
||||
else
|
||||
echo "$1 not found"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo 'No configuration file found...'
|
||||
exit 1
|
||||
if [[ -e reflector/urfd.ini ]]; then
|
||||
callsign=$(awk '$1 == "Callsign"{print $3}' reflector/urfd.ini)
|
||||
tcaddress=$(awk '$1 == "Transcoder"{print $3}' reflector/urfd.ini)
|
||||
else
|
||||
echo "ERROR: could not find reflector/urfd.ini! You'll have to specify it."
|
||||
echo "Usage: ./radmin PATH-TO-INI-FILE"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
key='x'
|
||||
# main loop
|
||||
@@ -104,18 +94,13 @@ do
|
||||
if [ "$pcount" -gt 1 ]; then
|
||||
echo
|
||||
ps -aux | head -1
|
||||
ps -aux | grep -e urfd -e tcd | grep -v grep
|
||||
ps -aux | grep -e urfd -e tcd | grep -v grep | grep -v radmin
|
||||
fi
|
||||
echo
|
||||
echo " Reflector Administration, Version #211204"
|
||||
echo " Reflector Administration, Version #230308"
|
||||
echo
|
||||
git status | head -1
|
||||
echo
|
||||
echo "ls : List the configuration file"
|
||||
echo "cl : Clean (remove) compiled objects and executables"
|
||||
echo "gp : Pull the latest software from the repo"
|
||||
echo "br : Change git branch to <value>"
|
||||
echo "co : Compile the system executable(s)"
|
||||
if [ -e $urfserv ]; then
|
||||
if [ -e $urfserv ]; then
|
||||
echo "us : Uninstall the URF reflector"
|
||||
@@ -146,11 +131,7 @@ do
|
||||
echo
|
||||
read -p "Please input <key> <value> - omit value to toggle a true/false : " key value garbage
|
||||
|
||||
if [[ "$key" == ls* ]]; then
|
||||
cat reflector.cfg;
|
||||
echo
|
||||
read -p "<Enter> to return to main menu: " ans
|
||||
elif [[ "$key" == us* ]]; then
|
||||
if [[ "$key" == us* ]]; then
|
||||
if [ -e $urfserv ]; then
|
||||
UninstallReflector
|
||||
fi
|
||||
@@ -158,33 +139,8 @@ do
|
||||
if [ -e reflector/urfd ] && [ ! -e $urfserv ]; then
|
||||
InstallReflector
|
||||
fi
|
||||
elif [[ "$key" == gp* ]]; then
|
||||
echo
|
||||
git pull
|
||||
echo
|
||||
read -p "<Enter> to continue: " ans
|
||||
pushd ../tcd
|
||||
git pull
|
||||
echo
|
||||
read -p "<Enter> to continue: " ans
|
||||
popd
|
||||
elif [[ "$key" == br* ]]; then
|
||||
echo
|
||||
git checkout "$value"
|
||||
echo
|
||||
read -p "<Enter> to continue: " ans
|
||||
pushd ../tcd
|
||||
git checkout "$value"
|
||||
echo
|
||||
read -p "<Enter> to continue: " ans
|
||||
popd
|
||||
elif [[ "$key" == rr* ]]; then
|
||||
if [ -e $urfserv ]; then
|
||||
sudo systemctl restart urfd
|
||||
fi
|
||||
elif [[ "$key" == rr* ]] && [ -e $urfserv ]; then sudo systemctl restart urfd
|
||||
elif [[ "$key" == tr* ]] && [ -e $tcdserv ]; then sudo systemctl restart tcd
|
||||
elif [[ "$key" == cl* ]]; then Clean
|
||||
elif [[ "$key" == co* ]]; then Compile
|
||||
elif [[ "$key" == tl* ]] && [ -e $tcdserv ]; then sudo journalctl -u tcd -f
|
||||
elif [[ "$key" == rl* ]] && [ -e $urfserv ]; then sudo journalctl -u urfd -f
|
||||
fi
|
||||
|
||||
@@ -1,653 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright (c) 2021 by Thomas A. Early N7TAE
|
||||
#
|
||||
# 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
#!/bin/bash
|
||||
|
||||
CharCount () {
|
||||
local haystack=$1
|
||||
local test="\${haystack//[^$2]}"
|
||||
eval local result=$test
|
||||
return ${#result}
|
||||
}
|
||||
|
||||
RemoveDupes () {
|
||||
local -n s=$1
|
||||
local i j
|
||||
for (( i=0; i<${#s}-1; i++)); do
|
||||
for (( j=$i+1; j<${#s}; j++)); do
|
||||
if [[ ${s:$i:1} != "." ]]; then
|
||||
if [[ ${s:$i:1} == ${s:$j:1} ]]; then
|
||||
local l=$(($j + 1))
|
||||
s="${s:0:$j}.${s:$l}"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
done
|
||||
s=${s//.}
|
||||
}
|
||||
|
||||
CheckModules () {
|
||||
# only A through Z
|
||||
modules=${1//[^A-Z]}
|
||||
if (( ${#modules} < 1 )); then
|
||||
unset modules
|
||||
clear
|
||||
echo "ERROR: You must specify at least one module, A to Z!"
|
||||
echo
|
||||
read -p "<Enter> to continue: " ans
|
||||
return
|
||||
fi
|
||||
|
||||
RemoveDupes modules
|
||||
tcmodules=${modules:0:1}
|
||||
}
|
||||
|
||||
CheckTranscodedModules () {
|
||||
local tc=${1//[^A-Z]}
|
||||
local tcorig=$tc
|
||||
if (( ${#tc} < 1 )); then
|
||||
tcmodules=${modules:0:1}
|
||||
clear
|
||||
echo "ERROR: You must specify at least one module!"
|
||||
echo "If you aren't using a transcoder, set the transcoder"
|
||||
echo "address value to the default 'none'!"
|
||||
echo
|
||||
read -p "<Enter> to continue: " ans
|
||||
return
|
||||
fi
|
||||
|
||||
RemoveDupes tc
|
||||
|
||||
local m=$modules_d
|
||||
if [ ! -z ${modules+x} ]; then
|
||||
m=$modules
|
||||
fi
|
||||
|
||||
local i
|
||||
for ((i=0; i<${#tc}; i++)); do
|
||||
CharCount $m ${tc:$i:1}
|
||||
local count=$?
|
||||
if (( $count < 1 )); then
|
||||
local j=$((i+1))
|
||||
tc="${tc:0:$i}.${tc:$j}"
|
||||
fi
|
||||
done
|
||||
tc=${tc//.}
|
||||
|
||||
if (( ${#tc} < 1 )); then
|
||||
echo "ERROR: Module(s), '$tcorig', are not in the configure modules, '$m'!"
|
||||
echo
|
||||
read -p "<Enter> to continue: " ans
|
||||
tcmodules=${modules:0:1}
|
||||
return
|
||||
fi
|
||||
tcmodules=$tc
|
||||
}
|
||||
|
||||
SetBooleanValue ()
|
||||
{
|
||||
local dvname
|
||||
local cv
|
||||
if [ -z $2 ]; then
|
||||
if [ -z ${!1+x} ]; then
|
||||
if [[ "$1" == module_[abc]_* ]]; then
|
||||
echo matches
|
||||
dvname=${1//_[abc]_/_x_}
|
||||
else
|
||||
echo does not match
|
||||
dvname=${1}_d
|
||||
fi
|
||||
cv=${!dvname}
|
||||
else
|
||||
cv=${!1}
|
||||
fi
|
||||
if [[ $cv == [tT]* ]]; then
|
||||
eval ${1}=false
|
||||
else
|
||||
eval ${1}=true
|
||||
fi
|
||||
elif [[ "$2" == [tT]* ]]; then
|
||||
eval ${1}=true
|
||||
else
|
||||
eval ${1}=false
|
||||
fi
|
||||
}
|
||||
|
||||
EvaluateVar ()
|
||||
{
|
||||
if [ -z ${!1+x} ]; then
|
||||
if [ -z "${!2}" ]; then
|
||||
echo "'' <DEFAULT>"
|
||||
else
|
||||
echo "${!2} <DEFAULT>"
|
||||
fi
|
||||
else
|
||||
if [ -z "${!1}" ]; then
|
||||
echo "''"
|
||||
else
|
||||
echo "${!1}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
TestGainValue ()
|
||||
{
|
||||
if [[ "$1" =~ ^[-]?[0-9]+$ ]]; then
|
||||
if (( $1 >= -24 && $1 <= 24 )); then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
AudioGainMenu ()
|
||||
{
|
||||
while [[ "$key" != q* ]]
|
||||
do
|
||||
clear
|
||||
echo
|
||||
echo " DVSI AMBE Chip Audio Gain Menu"
|
||||
echo
|
||||
echo " All values are in dB and can be from -24 to 24"
|
||||
echo " 'input' means the audio amplitude is adjusted before encoding"
|
||||
echo " 'output' means the audio amplitude is adjusted after decoding"
|
||||
echo
|
||||
echo " Non-zero values are generally not required!"
|
||||
echo " USE AT YOUR OWN RISK!"
|
||||
echo
|
||||
echo -n "si : D-Star audio input = "; EvaluateVar dstar_in_gain{,_d}
|
||||
echo -n "so : D-Star audio output = "; EvaluateVar dstar_out_gain{,_d}
|
||||
echo -n "mi : DMR/YSF audio input = "; EvaluateVar dmr_in_gain{,_d}
|
||||
echo -n "mo : DMR/YSF audio output = "; EvaluateVar dmr_out_gain{,_d}
|
||||
echo
|
||||
echo "q : Return to Main Menu"
|
||||
echo "u : Unset the value of <key> (revert to the default value)."
|
||||
echo
|
||||
read -p "Please input <key> <value> : " key value
|
||||
if [[ "$key" == si* ]]; then
|
||||
TestGainValue "$value" && dstar_in_gain="$value"
|
||||
elif [[ "$key" == so* ]]; then
|
||||
TestGainValue "$value" && dstar_out_gain="$value"
|
||||
elif [[ "$key" == mi* ]]; then
|
||||
TestGainValue "$value" && dmr_in_gain="$value"
|
||||
elif [[ "$key" == mo* ]]; then
|
||||
TestGainValue "$value" && dmr_out_gain="$value"
|
||||
elif [[ "$key" == u* ]]; then
|
||||
if [[ "$value" == si* ]]; then
|
||||
unset dstar_in_gain
|
||||
elif [[ "$value" == so* ]]; then
|
||||
unset dstar_out_gain
|
||||
elif [[ "$value" == mi* ]]; then
|
||||
unset dmr_in_gain
|
||||
elif [[ "$value" == mo* ]]; then
|
||||
unset dmr_out_gain
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
WriteMemFile ()
|
||||
{
|
||||
local file
|
||||
file="$rcfg"
|
||||
echo "# created on `date`" > $file
|
||||
[ -z ${callsign+x} ] || echo "callsign='$callsign'" >> $file
|
||||
[ -z ${modules+x} ] || echo "modules='$modules'" >> $file
|
||||
[ -z ${ip4addr+x} ] || echo "ip4addr='$ip4addr'" >> $file
|
||||
[ -z ${ip6addr+x} ] || echo "ip6addr='$ip6addr'" >> $file
|
||||
[ -z ${tcaddress+x} ] || echo "tcaddress='$tcaddress'" >> $file
|
||||
[ -z ${tcmodules+x} ] || echo "tcmodules='$tcmodules'" >> $file
|
||||
[ -z ${dstar_in_gain+x} ] || echo "dstar_in_gain=$dstar_in_gain" >> $file
|
||||
[ -z ${dstar_out_gain+x} ] || echo "dstar_out_gain=$dstar_out_gain" >> $file
|
||||
[ -z ${dmr_in_gain+x} ] || echo "dmr_in_gain=$dmr_in_gain" >> $file
|
||||
[ -z ${dmr_out_gain+x} ] || echo "dmr_out_gain=$dmr_out_gain" >> $file
|
||||
[ -z ${dmrdbuseserver+x} ] || echo "dmrdbuseserver=$dmrdbuseserver" >> $file
|
||||
[ -z ${dmrdbrefresh+x} ] || echo "dmrdbrefresh=$dmrdbrefresh" >> $file
|
||||
[ -z ${dmrdbpath+x} ] || echo "dmrdbpath='$dmrdbpath'" >> $file
|
||||
[ -z ${ysfautolink+x} ] || echo "ysfautolink=$ysfautolink" >> $file
|
||||
[ -z ${ysfmodule+x} ] || echo "ysfmodule='$ysfmodule'" >> $file
|
||||
[ -z ${ysflocaldb+x} ] || echo "ysflocaldb=$ysflocaldb" >> $file
|
||||
[ -z ${ysfdbname+x} ] || echo "ysfdbname='$ysfdbname'" >> $file
|
||||
[ -z ${ysfdbuser+x} ] || echo "ysfdbuser='$ysfdbuser'" >> $file
|
||||
[ -z ${ysfrname+x} ] || echo "ysfrname='$ysfrname'" >> $file
|
||||
[ -z ${ysfrdesc+x} ] || echo "ysfrdesc='$ysfrdesc'" >> $file
|
||||
[ -z ${ysfdbpw+x} ] || echo "ysfdbpw='$ysfdbpw'" >> $file
|
||||
[ -z ${g3support+x} ] || echo "g3support=$g3support" >> $file
|
||||
[ -z ${dbsupport+x} ] || echo "dbsupport=$dbsupport" >> $file
|
||||
}
|
||||
|
||||
WriteSRCHFile ()
|
||||
{
|
||||
local file m
|
||||
file="$srch"
|
||||
echo "// Created on `date`" > $file
|
||||
echo "#define CALLSIGN \"${callsign}\"" >> $file
|
||||
if [[ "$callsign" == XRF* ]]; then
|
||||
echo "#define NO_XLX" >> $file
|
||||
fi
|
||||
if [ -z ${modules+x} ]; then
|
||||
echo "#define ACTIVE_MODULES \"${modules_d}\"" >> $file
|
||||
else
|
||||
echo "#define ACTIVE_MODULES \"${modules}\"" >> $file
|
||||
fi
|
||||
if [ ! -z ${ip4addr+x} ]; then
|
||||
echo "#define LISTEN_IPV4 \"${ip4addr}\"" >> $file
|
||||
fi
|
||||
if [ ! -z ${ip6addr+x} ]; then
|
||||
echo "#define LISTEN_IPV6 \"${ip6addr}\"" >> $file
|
||||
fi
|
||||
if [ -z ${ysfautolink+x} ]; then
|
||||
echo "#define YSF_AUTOLINK_ENABLE ${ysfautolink_d}" >> $file
|
||||
else
|
||||
echo "#define YSF_AUTOLINK_ENABLE ${ysfautolink}" >> $file
|
||||
fi
|
||||
if [ -z ${ysfmodule+x} ]; then
|
||||
echo "#define YSF_AUTOLINK_MODULE '${ysfmodule_d}'" >> $file
|
||||
else
|
||||
echo "#define YSF_AUTOLINK_MODULE '${ysfmodule}'" >> $file
|
||||
fi
|
||||
if [ ! -z ${dmrdbuseserver+x} ]; then
|
||||
if [[ "$dmrdbuseserver" == true ]]; then
|
||||
m=1
|
||||
else
|
||||
m=0
|
||||
fi
|
||||
else
|
||||
m=1
|
||||
fi
|
||||
echo "#define DMRIDDB_USE_RLX_SERVER $m" >> $file
|
||||
if [ ! -z ${dmrdbrefresh+x} ]; then
|
||||
echo "#define DMRIDDB_REFRESH_RATE $dmrdbrefresh" >> $file
|
||||
else
|
||||
echo "#define DMRIDDB_REFRESH_RATE $dmrdbrefresh_d" >> $file
|
||||
fi
|
||||
if [ ! -z ${dmrdbpath+x} ]; then
|
||||
echo "#define DMRIDDB_PATH \"$dmrdbpath\"" >> $file
|
||||
else
|
||||
echo "#define DMRIDDB_PATH \"$dmrdbpath_d\"" >> $file
|
||||
fi
|
||||
if [[ "$ysflocaldb" == true ]]; then
|
||||
echo '#define YSF_DB_SUPPORT true' >> $file
|
||||
echo "#define YSF_DB_NAME \"$ysfdbname\"" >> $file
|
||||
echo "#define YSF_DB_USER \"$ysfdbuser\"" >> $file
|
||||
echo "#define YSF_DB_PASSWORD \"$ysfdbpw\"" >> $file
|
||||
else
|
||||
echo '#define YSF_DB_SUPPORT false' >> $file
|
||||
fi
|
||||
if [ ! -z ${ysfrname+x} ]; then
|
||||
echo "#define YSF_REFLECTOR_NAME \"$ysfrname\"" >> $file
|
||||
fi
|
||||
if [ ! -z ${ysfrdesc+x} ]; then
|
||||
echo "#define YSF_REFLECTOR_DESCRIPTION \"$ysfrdesc\"" >> $file
|
||||
fi
|
||||
if [ ! -z ${tcaddress+x} ]; then
|
||||
echo "#define TRANSCODER_IP \"${tcaddress}\"" >> $file
|
||||
echo "#define TRANSCODED_MODULES \"${tcmodules}\"" >> $file
|
||||
fi
|
||||
if [ -z ${g3support+x} ]; then
|
||||
m=${g3support_d}
|
||||
else
|
||||
m=${g3support}
|
||||
fi
|
||||
if [[ "$m" != true ]]; then
|
||||
echo "#define NO_G3" >> $file
|
||||
fi
|
||||
if [ -n ${dbsupport+x} ]; then
|
||||
if [ "$dbsupport" == true ]; then
|
||||
echo "#define DEBUG" >> $file
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
WriteSRCMKFile ()
|
||||
{
|
||||
local file
|
||||
file="$srcm"
|
||||
echo "# Created on `date`" > $file
|
||||
[ -z ${ip4addr+x} ] || echo "ipv4 = $ip4addr" >> $file
|
||||
[ -z ${ip6addr+x} ] || echo "ipv6 = $ip6addr" >> $file
|
||||
[ -z ${tcaddress+x} ] || echo "tc_ip = $tcaddress" >> $file
|
||||
if [ -z ${g3support+x} ]; then
|
||||
echo "use_g3 = $g3support_d" >> $file
|
||||
else
|
||||
echo "use_g3 = $g3support" >> $file
|
||||
fi
|
||||
if [ -z ${dbsupport+x} ]; then
|
||||
echo "debug = $dbsupport_d" >> $file
|
||||
else
|
||||
echo "debug = $dbsupport" >> $file
|
||||
fi
|
||||
if [ -z ${ysflocaldb+x} ]; then
|
||||
echo "ysf_db = $ysflocaldb_d" >> $file
|
||||
else
|
||||
echo "ysf_db = $ysflocaldb" >> $file
|
||||
fi
|
||||
}
|
||||
|
||||
WriteTranscoderHFile ()
|
||||
{
|
||||
local file
|
||||
file="$tcdh"
|
||||
echo "// Created on `date`" > $file
|
||||
if [ -n ${tcaddress+x} ] && [[ "$tcaddress" != "local" ]]; then
|
||||
echo "#define TRANSCODER_IP \"${tcaddress}\"" >> $file
|
||||
fi
|
||||
if [ -n ${tcmodules+x} ]; then
|
||||
echo "#define TRANSCODED_MODULES \"${tcmodules}\"" >> $file
|
||||
fi
|
||||
if [ -z ${dstar_in_gain+x} ]; then
|
||||
echo "#define DSTAR_IN_GAIN $dstar_in_gain_d" >> $file
|
||||
else
|
||||
echo "#define DSTAR_IN_GAIN $dstar_in_gain" >> $file
|
||||
fi
|
||||
if [ -z ${dstar_out_gain+x} ]; then
|
||||
echo "#define DSTAR_OUT_GAIN $dstar_out_gain_d" >> $file
|
||||
else
|
||||
echo "#define DSTAR_OUT_GAIN $dstar_out_gain" >> $file
|
||||
fi
|
||||
if [ -z ${dmr_in_gain+x} ]; then
|
||||
echo "#define DMR_IN_GAIN $dmr_in_gain_d" >> $file
|
||||
else
|
||||
echo "#define DMR_IN_GAIN $dmr_in_gain" >> $file
|
||||
fi
|
||||
if [ -z ${dmr_out_gain+x} ]; then
|
||||
echo "#define DMR_OUT_GAIN $dmr_out_gain_d" >> $file
|
||||
else
|
||||
echo "#define DMR_OUT_GAIN $dmr_out_gain" >> $file
|
||||
fi
|
||||
if [ -n ${dbsupport+x} ]; then
|
||||
if [ "$dbsupport" == true ]; then
|
||||
echo "#define DEBUG" >> $file
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
WriteTranscoderMKFile ()
|
||||
{
|
||||
local file
|
||||
file="$tcdm"
|
||||
echo "# created on `date`" > $file
|
||||
if [ -z ${dbsupport+x} ]; then
|
||||
echo "debug = $dbsupport_d" >> $file
|
||||
else
|
||||
echo "debug = $dbsupport" >> $file
|
||||
fi
|
||||
}
|
||||
|
||||
WriteCfgPhpFile ()
|
||||
{
|
||||
cat << EOF > $ysfs
|
||||
<?php
|
||||
define('DB_SERVER', 'localhost');
|
||||
define('DB_USERNAME', '${ysfdbuser}');
|
||||
define('DB_PASSWORD', '${ysfdbpw}');
|
||||
define('DB_NAME', '${ysfdbname}');
|
||||
// Attempt to connect to MySQL database
|
||||
\$link = mysqli_connect(DB_SERVER, DB_USERNAME, DB_PASSWORD, DB_NAME);
|
||||
// Check connection
|
||||
if (\$link === false) { die("ERROR: Could not connect. " . mysqli_connect_error()); }
|
||||
?>
|
||||
EOF
|
||||
}
|
||||
|
||||
WriteDBCreateFile ()
|
||||
{
|
||||
cat << EOF > $dbcr
|
||||
CREATE DATABASE IF NOT EXISTS ${ysfdbname};
|
||||
USE ${ysfdbname};
|
||||
CREATE TABLE IF NOT EXISTS ysfnodes (
|
||||
callsign VARCHAR(7) PRIMARY KEY,
|
||||
password VARCHAR(255) NOT NULL,
|
||||
txfreq INT NOT NULL DEFAULT 446500000,
|
||||
rxfreq INT NOT NULL DEFAULT 446500000,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE USER IF NOT EXISTS '${ysfdbuser}'@'localhost' IDENTIFIED BY '${ysfdbpw}';
|
||||
GRANT ALL PRIVILEGES ON $ysfdbname . ysfnodes TO '${ysfdbuser}'@'localhost';
|
||||
FLUSH PRIVILEGES;
|
||||
EOF
|
||||
}
|
||||
|
||||
WriteCFGFiles ()
|
||||
{
|
||||
WriteMemFile
|
||||
WriteSRCHFile
|
||||
WriteSRCMKFile
|
||||
if [ -z ${tcaddress+x} ]; then
|
||||
rm -f $tcdh $tcdm
|
||||
else
|
||||
WriteTranscoderHFile
|
||||
WriteTranscoderMKFile
|
||||
fi
|
||||
if [[ "$ysflocaldb" == true ]]; then
|
||||
WriteCfgPhpFile
|
||||
WriteDBCreateFile
|
||||
else
|
||||
rm -f $ysfs $dbcr
|
||||
fi
|
||||
}
|
||||
|
||||
ListCFGFiles ()
|
||||
{
|
||||
echo "===========${rcfg}============="
|
||||
cat $rcfg
|
||||
echo "===========${srch}============="
|
||||
cat $srch
|
||||
echo "===========${srcm}============="
|
||||
cat $srcm
|
||||
if [ ! -z ${tcaddress+x} ]; then
|
||||
echo "===========${tcdh}============="
|
||||
cat $tcdh
|
||||
echo "===========${tcdm}============="
|
||||
cat $tcdm
|
||||
fi
|
||||
if [[ "$ysflocaldb" == true ]]; then
|
||||
echo "===========${ysfs}============="
|
||||
cat $ysfs
|
||||
echo "===========${dbcr}============="
|
||||
cat $dbcr
|
||||
fi
|
||||
}
|
||||
|
||||
# Execution starts here!
|
||||
# file locations
|
||||
rcfg='reflector.cfg'
|
||||
srch='reflector/configure.h'
|
||||
srcm='reflector/configure.mk'
|
||||
tcdh='../tcd/configure.h'
|
||||
tcdm='../tcd/configure.mk'
|
||||
ysfs='wiresx/configure.php'
|
||||
dbcr='configure.sql'
|
||||
urfserv='/etc/systemd/system/urfd.service'
|
||||
|
||||
# expert mode
|
||||
if [[ "$1" == ex* ]]; then
|
||||
expertmode="expertMode"
|
||||
fi
|
||||
|
||||
if [ -e reflector.cfg ]; then
|
||||
source reflector.cfg
|
||||
else
|
||||
echo 'No configuration file found...'
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
# default values
|
||||
callsign_d='CHNGME'
|
||||
modules_d='ABCF'
|
||||
ip4addr_d='none'
|
||||
ip6addr_d='none'
|
||||
tcaddress_d='none'
|
||||
ysfautolink_d=false
|
||||
ysfmodule_d='D'
|
||||
g3support_d=false
|
||||
dbsupport_d=false
|
||||
dmrdbuseserver_d=true
|
||||
dmrdbrefresh_d=180
|
||||
dmrdbpath_d='/usr/local/etc/dmrid.dat'
|
||||
ysflocaldb_d=false
|
||||
ysfdbname_d=''
|
||||
ysfdbuser_d=''
|
||||
ysfdbpw_d=''
|
||||
dstar_in_gain_d=0
|
||||
dstar_out_gain_d=0
|
||||
dmr_in_gain_d=0
|
||||
dmr_out_gain_d=0
|
||||
if [ -z ${callsign+x} ];then
|
||||
ysfrname_d="$callsign_d"
|
||||
else
|
||||
ysfrname_d="$callsign"
|
||||
fi
|
||||
ysfrdesc_d='URF Reflector'
|
||||
|
||||
if [ -z ${expertmode+x} ]; then
|
||||
if [ -e $urfserv ]; then
|
||||
echo -n "You cannot change the configuration right now beacuse there is an "
|
||||
if [ -e $urfserv ]; then
|
||||
echo "URFD server running."
|
||||
fi;
|
||||
echo "===========${rcfg}============="
|
||||
cat $rcfg
|
||||
echo
|
||||
echo "Please use radmin to uninstall the running server before attempting to modify the configuration."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
key='x'
|
||||
# main loop
|
||||
while [[ "$key" != q* ]]
|
||||
do
|
||||
clear
|
||||
echo
|
||||
echo " Reflector Configuration, Version #220326"
|
||||
echo
|
||||
echo " ******* REFLECTOR ********"
|
||||
echo -n "cs : Reflector Callsign = "; EvaluateVar callsign{,_d}
|
||||
echo -n "am : Active Modules = "; EvaluateVar modules{,_d}
|
||||
echo -n "g3 : Icom G3 Support = "; EvaluateVar g3support{,_d}
|
||||
echo " ******* ADDRESSES ********"
|
||||
echo -n "i4 : IPv4 Listen Address = "; EvaluateVar ip4addr{,_d}
|
||||
echo -n "i6 : IPv6 Listen Address = "; EvaluateVar ip6addr{,_d}
|
||||
echo " ******* TRANSCODER ********"
|
||||
echo " The only TC address supported is 'local' or the default 'none'"
|
||||
echo -n "tc : Transcoder Address = "; EvaluateVar tcaddress{,_d}
|
||||
if [ ! -z ${tcaddress+x} ]; then
|
||||
echo -n "tm : Transcoder Modules = "; EvaluateVar tcmodules{,_d}
|
||||
echo "ag : AMBE Audio Gain Sub-Menu"
|
||||
if [ ! -z ${dstar_in_gain+x} ]; then
|
||||
echo -n " D-Star Input gain = "; EvaluateVar dstar_in_gain{,_d}
|
||||
fi
|
||||
if [ ! -z ${dstar_out_gain+x} ]; then
|
||||
echo -n " D-Star Output gain = "; EvaluateVar dstar_out_gain{,_d}
|
||||
fi
|
||||
if [ ! -z ${dmr_in_gain+x} ]; then
|
||||
echo -n " DMR Input gain = "; EvaluateVar dmr_in_gain{,_d}
|
||||
fi
|
||||
if [ ! -z ${dmr_out_gain+x} ]; then
|
||||
echo -n " DMR Output gain = "; EvaluateVar dmr_out_gain{,_d}
|
||||
fi
|
||||
fi
|
||||
echo " ******* DMR Database ********"
|
||||
echo -n "ds : Use RLX Server = "; EvaluateVar dmrdbuseserver{,_d}
|
||||
echo -n "dt : Refresh time (in min) = "; EvaluateVar dmrdbrefresh{,_d}
|
||||
echo -n "dp : Database path = "; EvaluateVar dmrdbpath{,_d}
|
||||
echo " ******* SYSTEM FUSION ********"
|
||||
echo -n "ye : YSF Autolink Enable = "; EvaluateVar ysfautolink{,_d}
|
||||
if [ ! -z ${ysfautolink+x} ]; then
|
||||
if [[ "$ysfautolink" == true ]]; then
|
||||
echo -n "ym : YSF Autolink Module = "; EvaluateVar ysfmodule{,_d}
|
||||
fi
|
||||
fi
|
||||
echo -n "yl : YSF Local Database = "; EvaluateVar ysflocaldb{,_d}
|
||||
if [[ "$ysflocaldb" == true ]]; then
|
||||
echo -n "yd : YSF Database Name = "; EvaluateVar ysfdbname{,_d}
|
||||
echo -n "yu : YSF Database User = "; EvaluateVar ysfdbuser{,_d}
|
||||
echo -n "yp : YSF Database Password = "; EvaluateVar ysfdbpw{,_d}
|
||||
fi
|
||||
echo " ******* YSFReflector Registry *******"
|
||||
echo -n "rn : Registry Name = "; EvaluateVar ysfrname{,_d}
|
||||
echo -n "rd : Registry Description = "; EvaluateVar ysfrdesc{,_d}
|
||||
echo " ******* DEBUGGING ********"
|
||||
echo -n "db : Debugging Support = "; EvaluateVar dbsupport{,_d}
|
||||
echo
|
||||
if [[ "$callsign" == URF* ]]; then
|
||||
echo "w : Write configuration files (overwrites any existing files) and quit"
|
||||
fi
|
||||
echo "q : Quit without saving"
|
||||
echo "u : Unset the value of <key> (revert to the default value)."
|
||||
echo
|
||||
read -p "Please input <key> <value> - omit value to toggle a true/false : " key value
|
||||
|
||||
if [[ "$key" == cs* && ${value^^} == URF* ]]; then
|
||||
callsign="${value^^}"
|
||||
callsign="${callsign:0:6}"
|
||||
ysfrname_d="${callsign}"
|
||||
unset tcaddress tcmodules ysf{autolink,module,localdb,dbname,dbuser,dbpw}
|
||||
elif [[ "$key" == am* ]]; then CheckModules "${value^^}"
|
||||
elif [[ "$key" == i4* ]]; then ip4addr="$value"
|
||||
elif [[ "$key" == i6* ]]; then ip6addr="$value"
|
||||
elif [[ "$key" == tc* ]]; then tcaddress="local"
|
||||
elif [[ "$key" == tm* ]]; then CheckTranscodedModules "${value^^}"
|
||||
elif [[ "$key" == ag* ]]; then
|
||||
AudioGainMenu
|
||||
key=x
|
||||
elif [[ "$key" == ds* ]]; then SetBooleanValue dmrdbuseserver "$value"
|
||||
elif [[ "$key" == dt* ]]; then dmrdbrefresh="$value"
|
||||
elif [[ "$key" == dp* ]]; then dmrdbpath="$value"
|
||||
elif [[ "$key" == ye* ]]; then SetBooleanValue ysfautolink "$value"
|
||||
elif [[ "$key" == ym* ]]; then
|
||||
ysfmodule="${value^^}"
|
||||
ysfmodule="${ysfmodule:0:1}"
|
||||
elif [[ "$key" == g3* ]]; then SetBooleanValue g3support "$value"
|
||||
elif [[ "$key" == db* ]]; then SetBooleanValue dbsupport "$value"
|
||||
elif [[ "$key" == yl* ]]; then SetBooleanValue ysflocaldb "$value"
|
||||
elif [[ "$key" == yd* ]]; then ysfdbname="$value"
|
||||
elif [[ "$key" == yu* ]]; then ysfdbuser="$value"
|
||||
elif [[ "$key" == yp* ]]; then ysfdbpw="$value"
|
||||
elif [[ "$key" == rn* ]]; then ysfrname="${value:0:16}"
|
||||
elif [[ "$key" == rd* ]]; then ysfrdesc="${value:0:14}"
|
||||
elif [[ "$key" == w* ]]; then
|
||||
WriteCFGFiles
|
||||
ListCFGFiles
|
||||
exit 0
|
||||
elif [[ "$key" == u* ]]; then
|
||||
if [[ "$value" == cs* ]]; then unset callsign
|
||||
elif [[ "$value" == am* ]]; then unset modules
|
||||
elif [[ "$value" == i4* ]]; then unset ip4addr
|
||||
elif [[ "$value" == i6* ]]; then unset ip6addr
|
||||
elif [[ "$value" == tc* ]]; then unset tcaddress
|
||||
elif [[ "$value" == tm* ]]; then tcmodules=${modules:0:1}
|
||||
elif [[ "$value" == ds* ]]; then unset dmrdbuseserver
|
||||
elif [[ "$value" == dt* ]]; then unset dmrdbrefresh
|
||||
elif [[ "$value" == dp* ]]; then unset dmrdbpath
|
||||
elif [[ "$value" == ye* ]]; then unset ysfautolink ysfmodule
|
||||
elif [[ "$value" == ym* ]]; then unset ysfmodule
|
||||
elif [[ "$value" == g3* ]]; then unset g3support
|
||||
elif [[ "$value" == db* ]]; then unset dbsupport
|
||||
elif [[ "$value" == yl* ]]; then unset ysflocaldb ysfdbname ysfdbuser ysfdbpw
|
||||
elif [[ "$value" == yd* ]]; then unset ysfdbname
|
||||
elif [[ "$value" == yu* ]]; then unset ysfdbuser
|
||||
elif [[ "$value" == yp* ]]; then unset ysfdbpw
|
||||
elif [[ "$value" == rn* ]]; then unset ysfrname
|
||||
elif [[ "$value" == rd* ]]; then unset ysfrdesc
|
||||
fi
|
||||
fi
|
||||
done
|
||||
exit 0
|
||||
@@ -17,7 +17,7 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <string.h>
|
||||
#include "Main.h"
|
||||
|
||||
#include "BMClient.h"
|
||||
|
||||
|
||||
@@ -43,5 +43,5 @@ CBmClient::CBmClient(const CBmClient &client)
|
||||
|
||||
bool CBmClient::IsAlive(void) const
|
||||
{
|
||||
return (m_LastKeepaliveTime.time() < XLX_KEEPALIVE_TIMEOUT);
|
||||
return (m_LastKeepaliveTime.time() < BM_KEEPALIVE_TIMEOUT);
|
||||
}
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Defines.h"
|
||||
#include "Client.h"
|
||||
|
||||
class CBmClient : public CClient
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
#include "Main.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "Reflector.h"
|
||||
#include "BMPeer.h"
|
||||
@@ -50,7 +50,7 @@ CBmPeer::CBmPeer(const CCallsign &callsign, const CIp &ip, const char *modules,
|
||||
|
||||
bool CBmPeer::IsAlive(void) const
|
||||
{
|
||||
return (m_LastKeepaliveTime.time() < XLX_KEEPALIVE_TIMEOUT);
|
||||
return (m_LastKeepaliveTime.time() < BM_KEEPALIVE_TIMEOUT);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
+11
-16
@@ -18,18 +18,16 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "Main.h"
|
||||
#include "BMPeer.h"
|
||||
#include "BMProtocol.h"
|
||||
#include "Reflector.h"
|
||||
#include "GateKeeper.h"
|
||||
|
||||
#include "Global.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// operation
|
||||
|
||||
bool CBMProtocol::Initialize(const char *type, const EProtocol ptype, const uint16_t port, const bool has_ipv4, const bool has_ipv6)
|
||||
{
|
||||
m_HasTranscoder = g_Configure.IsString(g_Keys.modules.tcmodules);
|
||||
if (! CProtocol::Initialize(type, ptype, port, has_ipv4, has_ipv6))
|
||||
return false;
|
||||
|
||||
@@ -167,7 +165,7 @@ void CBMProtocol::Task(void)
|
||||
HandleQueue();
|
||||
|
||||
// keep alive
|
||||
if ( m_LastKeepaliveTime.time() > XLX_KEEPALIVE_PERIOD )
|
||||
if ( m_LastKeepaliveTime.time() > BM_KEEPALIVE_PERIOD )
|
||||
{
|
||||
// handle keep alives
|
||||
HandleKeepalives();
|
||||
@@ -177,7 +175,7 @@ void CBMProtocol::Task(void)
|
||||
}
|
||||
|
||||
// peer connections
|
||||
if ( m_LastPeersLinkTime.time() > XLX_RECONNECT_PERIOD )
|
||||
if ( m_LastPeersLinkTime.time() > BM_RECONNECT_PERIOD )
|
||||
{
|
||||
// handle remote peers connections
|
||||
HandlePeerLinks();
|
||||
@@ -192,11 +190,10 @@ void CBMProtocol::Task(void)
|
||||
|
||||
void CBMProtocol::HandleQueue(void)
|
||||
{
|
||||
m_Queue.Lock();
|
||||
while ( !m_Queue.empty() )
|
||||
while (! m_Queue.IsEmpty())
|
||||
{
|
||||
// get the packet
|
||||
auto packet = m_Queue.pop();
|
||||
auto packet = m_Queue.Pop();
|
||||
|
||||
// encode it
|
||||
CBuffer buffer;
|
||||
@@ -228,11 +225,10 @@ void CBMProtocol::HandleQueue(void)
|
||||
break;
|
||||
case EProtoRev::ambe:
|
||||
default:
|
||||
#ifdef TRANSCODED_MODULES
|
||||
Send(buffer, client->GetIp());
|
||||
#else
|
||||
Send(bufferLegacy, client->GetIp());
|
||||
#endif
|
||||
if (m_HasTranscoder)
|
||||
Send(buffer, client->GetIp());
|
||||
else
|
||||
Send(bufferLegacy, client->GetIp());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -240,7 +236,6 @@ void CBMProtocol::HandleQueue(void)
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
}
|
||||
m_Queue.Unlock();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -324,7 +319,7 @@ void CBMProtocol::HandlePeerLinks(void)
|
||||
it->ResolveIp();
|
||||
// send connect packet to re-initiate peer link
|
||||
EncodeConnectPacket(&buffer, it->GetModules());
|
||||
Send(buffer, it->GetIp(), XLX_PORT);
|
||||
Send(buffer, it->GetIp(), m_Port);
|
||||
std::cout << "Sending connect packet to BM peer " << cs << " @ " << it->GetIp() << " for modules " << it->GetModules() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Defines.h"
|
||||
#include "Version.h"
|
||||
#include "Timer.h"
|
||||
#include "SEProtocol.h"
|
||||
@@ -72,4 +73,6 @@ protected:
|
||||
// time
|
||||
CTimer m_LastKeepaliveTime;
|
||||
CTimer m_LastPeersLinkTime;
|
||||
// config data;
|
||||
bool m_HasTranscoder;
|
||||
};
|
||||
@@ -16,6 +16,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <iostream>
|
||||
#include <string.h>
|
||||
#include "Buffer.h"
|
||||
|
||||
@@ -175,7 +176,7 @@ CBuffer::operator const char *() const
|
||||
|
||||
void CBuffer::DebugDump(std::ofstream &debugout) const
|
||||
{
|
||||
// dump an hex line
|
||||
// dump a hex line
|
||||
for ( unsigned int i = 0; i < m_data.size(); i++ )
|
||||
{
|
||||
char sz[16];
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include "Main.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -23,12 +23,6 @@
|
||||
|
||||
#include "Notification.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CNotificationQueue
|
||||
{
|
||||
public:
|
||||
|
||||
+26
-11
@@ -27,6 +27,18 @@
|
||||
#define CALLSIGN_LEN 8
|
||||
#define CALLSUFFIX_LEN 4
|
||||
|
||||
union UCallsign
|
||||
{
|
||||
char c[CALLSIGN_LEN];
|
||||
uint64_t l;
|
||||
};
|
||||
|
||||
union USuffix
|
||||
{
|
||||
char c[CALLSUFFIX_LEN];
|
||||
uint32_t u;
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
@@ -36,7 +48,9 @@ class CCallsign
|
||||
public:
|
||||
// contructors
|
||||
CCallsign();
|
||||
CCallsign(const char *, uint32_t = 0, uint16_t = 0);
|
||||
CCallsign(const UCallsign &cs); // no id lookup
|
||||
CCallsign(const CCallsign &cs);
|
||||
CCallsign(const std::string &cs, uint32_t dmrid = 0, uint16_t nxdnid = 0);
|
||||
|
||||
// status
|
||||
bool IsValid(void) const;
|
||||
@@ -44,23 +58,24 @@ public:
|
||||
bool HasModule(void) const { return m_Module != ' '; }
|
||||
|
||||
// set
|
||||
void SetCallsign(const char *, bool = true);
|
||||
void SetCallsign(const std::string &s, bool updateids = true);
|
||||
void SetCallsign(const uint8_t *, int, bool = true);
|
||||
void SetDmrid(uint32_t, bool = true);
|
||||
void SetDmrid(const uint8_t *, bool = true);
|
||||
void SetNXDNid(uint16_t, bool = true);
|
||||
void SetNXDNid(const uint8_t *, bool = true);
|
||||
void SetCSModule(char);
|
||||
void SetSuffix(const char *);
|
||||
void SetSuffix(const std::string &s);
|
||||
void SetSuffix(const uint8_t *, int);
|
||||
|
||||
// modify
|
||||
void PatchCallsign(int, const char *, int);
|
||||
|
||||
// get
|
||||
UCallsign GetKey() const;
|
||||
void GetCallsign(uint8_t *) const;
|
||||
void GetCallsignString(char *) const;
|
||||
const std::string GetCS(unsigned len = 9) const;
|
||||
const std::string GetCS() const;
|
||||
uint32_t GetDmrid(void) const { return m_uiDmrid; }
|
||||
uint16_t GetNXDNid(void) const { return m_uiNXDNid; }
|
||||
void GetSuffix(uint8_t *) const;
|
||||
@@ -73,6 +88,7 @@ public:
|
||||
bool HasSameModule(const CCallsign &) const;
|
||||
|
||||
// operators
|
||||
CCallsign &operator = (const CCallsign &cs);
|
||||
bool operator ==(const CCallsign &) const;
|
||||
operator const char *() const;
|
||||
|
||||
@@ -92,11 +108,10 @@ protected:
|
||||
|
||||
protected:
|
||||
// data
|
||||
char m_Callsign[CALLSIGN_LEN];
|
||||
char m_Suffix[CALLSUFFIX_LEN];
|
||||
char m_Module;
|
||||
mutable char m_sz[CALLSIGN_LEN+CALLSUFFIX_LEN+5];
|
||||
uint32_t m_uiDmrid;
|
||||
uint16_t m_uiNXDNid;
|
||||
uint64_t m_coded; // M17 encoded callsign
|
||||
UCallsign m_Callsign;
|
||||
USuffix m_Suffix;
|
||||
char m_Module;
|
||||
uint32_t m_uiDmrid;
|
||||
uint16_t m_uiNXDNid;
|
||||
uint64_t m_coded; // M17 encoded callsign
|
||||
};
|
||||
@@ -16,10 +16,11 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <fstream>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include "Main.h"
|
||||
|
||||
#include "CallsignList.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -27,14 +28,13 @@
|
||||
|
||||
CCallsignList::CCallsignList()
|
||||
{
|
||||
m_Filename = nullptr;
|
||||
memset(&m_LastModTime, 0, sizeof(time_t));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// file io
|
||||
|
||||
bool CCallsignList::LoadFromFile(const char *filename)
|
||||
bool CCallsignList::LoadFromFile(const std::string &filename)
|
||||
{
|
||||
bool ok = false;
|
||||
char sz[256];
|
||||
@@ -77,7 +77,7 @@ bool CCallsignList::LoadFromFile(const char *filename)
|
||||
file.close();
|
||||
|
||||
// keep file path
|
||||
m_Filename = filename;
|
||||
m_Filename.assign(filename);
|
||||
|
||||
// update time
|
||||
GetLastModTime(&m_LastModTime);
|
||||
@@ -99,7 +99,7 @@ bool CCallsignList::ReloadFromFile(void)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
if ( m_Filename != nullptr )
|
||||
if (! m_Filename.empty())
|
||||
{
|
||||
ok = LoadFromFile(m_Filename);
|
||||
}
|
||||
@@ -210,10 +210,10 @@ bool CCallsignList::GetLastModTime(time_t *time)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
if ( m_Filename != nullptr )
|
||||
if (! m_Filename.empty())
|
||||
{
|
||||
struct stat fileStat;
|
||||
if( ::stat(m_Filename, &fileStat) != -1 )
|
||||
if( ::stat(m_Filename.c_str(), &fileStat) != -1 )
|
||||
{
|
||||
*time = fileStat.st_mtime;
|
||||
ok = true;
|
||||
|
||||
+10
-10
@@ -17,7 +17,10 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
#include "Main.h"
|
||||
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
|
||||
#include "CallsignListItem.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -29,15 +32,12 @@ public:
|
||||
// constructor
|
||||
CCallsignList();
|
||||
|
||||
// destructor
|
||||
virtual ~CCallsignList() {}
|
||||
|
||||
// locks
|
||||
void Lock(void) { m_Mutex.lock(); }
|
||||
void Unlock(void) { m_Mutex.unlock(); }
|
||||
void Lock(void) const { m_Mutex.lock(); }
|
||||
void Unlock(void) const { m_Mutex.unlock(); }
|
||||
|
||||
// file io
|
||||
virtual bool LoadFromFile(const char *);
|
||||
virtual bool LoadFromFile(const std::string &str);
|
||||
bool ReloadFromFile(void);
|
||||
bool NeedReload(void);
|
||||
|
||||
@@ -60,8 +60,8 @@ protected:
|
||||
char *TrimWhiteSpaces(char *);
|
||||
|
||||
// data
|
||||
std::mutex m_Mutex;
|
||||
const char * m_Filename;
|
||||
time_t m_LastModTime;
|
||||
mutable std::mutex m_Mutex;
|
||||
std::string m_Filename;
|
||||
time_t m_LastModTime;
|
||||
std::list<CCallsignListItem> m_Callsigns;
|
||||
};
|
||||
@@ -17,7 +17,9 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <string.h>
|
||||
#include "Main.h"
|
||||
|
||||
#include "Global.h"
|
||||
|
||||
#include "CallsignListItem.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -31,6 +33,7 @@ CCallsignListItem::CCallsignListItem()
|
||||
|
||||
CCallsignListItem::CCallsignListItem(const CCallsign &callsign, const CIp &ip, const char *modules)
|
||||
{
|
||||
const std::string mods(g_Configure.GetString(g_Keys.modules.modules));
|
||||
m_Callsign = callsign;
|
||||
memset(m_szUrl, 0, sizeof(m_szUrl));
|
||||
m_Ip = ip;
|
||||
@@ -39,14 +42,14 @@ CCallsignListItem::CCallsignListItem(const CCallsign &callsign, const CIp &ip, c
|
||||
memset(m_Modules, 0, sizeof(m_Modules));
|
||||
if ( modules[0] == '*' )
|
||||
{
|
||||
memcpy(m_Modules, ACTIVE_MODULES, sizeof(ACTIVE_MODULES));
|
||||
memcpy(m_Modules, mods.c_str(), mods.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
int n = MIN(::strlen(modules), sizeof(m_Modules)-1);
|
||||
for (int i=0, j=0; i<n; i++)
|
||||
{
|
||||
if (strchr(ACTIVE_MODULES, modules[i]))
|
||||
if (std::string::npos != mods.find(modules[i]))
|
||||
{
|
||||
m_Modules[j++] = modules[i];
|
||||
}
|
||||
@@ -57,6 +60,7 @@ CCallsignListItem::CCallsignListItem(const CCallsign &callsign, const CIp &ip, c
|
||||
|
||||
CCallsignListItem::CCallsignListItem(const CCallsign &callsign, const char *url, const char *modules)
|
||||
{
|
||||
const std::string mods(g_Configure.GetString(g_Keys.modules.modules));
|
||||
m_Callsign = callsign;
|
||||
::strncpy(m_szUrl, url, URL_MAXLEN);
|
||||
m_Ip = CIp(m_szUrl);
|
||||
@@ -65,14 +69,14 @@ CCallsignListItem::CCallsignListItem(const CCallsign &callsign, const char *url,
|
||||
memset(m_Modules, 0, sizeof(m_Modules));
|
||||
if ( modules[0] == '*' )
|
||||
{
|
||||
memcpy(m_Modules, ACTIVE_MODULES, sizeof(ACTIVE_MODULES));
|
||||
memcpy(m_Modules, mods.c_str(), mods.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
int n = MIN(::strlen(modules), sizeof(m_Modules)-1);
|
||||
for (int i=0, j=0; i<n; i++)
|
||||
{
|
||||
if (strchr(ACTIVE_MODULES, modules[i]))
|
||||
if (std::string::npos != mods.find(modules[i]))
|
||||
{
|
||||
m_Modules[j++] = modules[i];
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Main.h"
|
||||
|
||||
#include "Callsign.h"
|
||||
#include "IP.h"
|
||||
|
||||
|
||||
+10
-17
@@ -16,7 +16,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "Client.h"
|
||||
|
||||
@@ -96,21 +96,14 @@ void CClient::WriteXml(std::ofstream &xmlFile)
|
||||
xmlFile << "</NODE>" << std::endl;
|
||||
}
|
||||
|
||||
void CClient::GetJsonObject(char *Buffer)
|
||||
void CClient::JsonReport(nlohmann::json &report)
|
||||
{
|
||||
char sz[512];
|
||||
char mbstr[100];
|
||||
char cs[16];
|
||||
|
||||
if (std::strftime(mbstr, sizeof(mbstr), "%A %c", std::localtime(&m_LastHeardTime)))
|
||||
{
|
||||
m_Callsign.GetCallsignString(cs);
|
||||
|
||||
::sprintf(sz, "{\"callsign\":\"%s\",\"module\":\"%c\",\"linkedto\":\"%c\",\"time\":\"%s\"}",
|
||||
cs,
|
||||
m_Callsign.GetCSModule(),
|
||||
m_ReflectorModule,
|
||||
mbstr);
|
||||
::strcat(Buffer, sz);
|
||||
}
|
||||
nlohmann::json jclient;
|
||||
jclient["Callsign"] = m_Callsign.GetCS();
|
||||
jclient["OnModule"] = std::string(1, m_ReflectorModule);
|
||||
jclient["Protocol"] = GetProtocolName();
|
||||
char s[100];
|
||||
if (std::strftime(s, sizeof(s), "%FT%TZ", std::gmtime(&m_ConnectTime)))
|
||||
jclient["ConnectTime"] = s;
|
||||
report["Clients"].push_back(jclient);
|
||||
}
|
||||
+7
-4
@@ -18,6 +18,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include "Defines.h"
|
||||
#include "Timer.h"
|
||||
#include "IP.h"
|
||||
#include "Callsign.h"
|
||||
@@ -44,13 +47,13 @@ public:
|
||||
const CCallsign &GetCallsign(void) const { return m_Callsign; }
|
||||
const CIp &GetIp(void) const { return m_Ip; }
|
||||
bool HasModule(void) const { return m_Callsign.HasModule(); }
|
||||
char GetCSModule(void) const { return m_Callsign.GetCSModule(); }
|
||||
char GetCSModule(void) const { return m_Callsign.GetCSModule(); }
|
||||
bool HasReflectorModule(void) const { return m_ReflectorModule != ' '; }
|
||||
char GetReflectorModule(void) const { return m_ReflectorModule; }
|
||||
|
||||
// set
|
||||
void SetCSModule(char c) { m_Callsign.SetCSModule(c); }
|
||||
void SetReflectorModule(char c) { m_ReflectorModule = c; }
|
||||
void SetCSModule(char c) { m_Callsign.SetCSModule(c); }
|
||||
void SetReflectorModule(char c) { m_ReflectorModule = c; }
|
||||
|
||||
// identity
|
||||
virtual EProtocol GetProtocol(void) const { return EProtocol::none; }
|
||||
@@ -71,7 +74,7 @@ public:
|
||||
|
||||
// reporting
|
||||
virtual void WriteXml(std::ofstream &);
|
||||
virtual void GetJsonObject(char *);
|
||||
void JsonReport(nlohmann::json &report);
|
||||
|
||||
protected:
|
||||
// data
|
||||
|
||||
@@ -16,15 +16,13 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
#include "Reflector.h"
|
||||
#include "Clients.h"
|
||||
|
||||
#include "Global.h"
|
||||
#include "Clients.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor
|
||||
|
||||
|
||||
CClients::CClients()
|
||||
{
|
||||
}
|
||||
|
||||
+74
-44
@@ -16,29 +16,18 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "CodecStream.h"
|
||||
#include "DVFramePacket.h"
|
||||
#include "Reflector.h"
|
||||
#include "PacketStream.h"
|
||||
#include "CodecStream.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor
|
||||
|
||||
CCodecStream::CCodecStream(CPacketStream *PacketStream, uint16_t streamid, ECodecType type, std::shared_ptr<CUnixDgramReader> reader)
|
||||
CCodecStream::CCodecStream(CPacketStream *PacketStream, char module) : m_CSModule(module), m_IsOpen(false)
|
||||
{
|
||||
keep_running = true;
|
||||
m_uiStreamId = streamid;
|
||||
m_uiPid = 0;
|
||||
m_eCodecIn = type;
|
||||
m_RTMin = -1;
|
||||
m_RTMax = -1;
|
||||
m_RTSum = 0;
|
||||
m_RTCount = 0;
|
||||
m_uiTotalPackets = 0;
|
||||
m_PacketStream = PacketStream;
|
||||
m_TCReader = reader;
|
||||
InitCodecStream();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -52,7 +41,27 @@ CCodecStream::~CCodecStream()
|
||||
{
|
||||
m_Future.get();
|
||||
}
|
||||
// and close the socket
|
||||
m_TCReader.Close();
|
||||
}
|
||||
|
||||
void CCodecStream::ResetStats(uint16_t streamid, ECodecType type)
|
||||
{
|
||||
m_IsOpen = true;
|
||||
keep_running = true;
|
||||
m_uiStreamId = streamid;
|
||||
m_uiPid = 0;
|
||||
m_eCodecIn = type;
|
||||
m_RTMin = -1;
|
||||
m_RTMax = -1;
|
||||
m_RTSum = 0;
|
||||
m_RTCount = 0;
|
||||
m_uiTotalPackets = 0;
|
||||
}
|
||||
|
||||
void CCodecStream::ReportStats()
|
||||
{
|
||||
m_IsOpen = false;
|
||||
// display stats
|
||||
if (m_RTCount > 0)
|
||||
{
|
||||
@@ -61,7 +70,7 @@ CCodecStream::~CCodecStream()
|
||||
double ave = 1000.0 * m_RTSum / double(m_RTCount);
|
||||
auto prec = std::cout.precision();
|
||||
std::cout.precision(1);
|
||||
std::cout << std::fixed << "TC round-trip time(ms): " << min << "/" << ave << "/" << max << ", " << m_RTCount << " total packets" << std::endl;
|
||||
std::cout << std::fixed << "TC round-trip time(ms): " << min << '/' << ave << '/' << max << ", " << m_RTCount << " total packets" << std::endl;
|
||||
std::cout.precision(prec);
|
||||
}
|
||||
}
|
||||
@@ -69,11 +78,26 @@ CCodecStream::~CCodecStream()
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// initialization
|
||||
|
||||
void CCodecStream::InitCodecStream(void)
|
||||
bool CCodecStream::InitCodecStream()
|
||||
{
|
||||
m_TCWriter.SetUp(REF2TC);
|
||||
std::string name(TC2REF);
|
||||
name.append(1, m_CSModule);
|
||||
if (m_TCReader.Open(name.c_str()))
|
||||
return true;
|
||||
std::cout << "Initialized CodecStream receive socket " << name << std::endl;
|
||||
keep_running = true;
|
||||
m_Future = std::async(std::launch::async, &CCodecStream::Thread, this);
|
||||
try
|
||||
{
|
||||
m_Future = std::async(std::launch::async, &CCodecStream::Thread, this);
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
std::cerr << "Could not start Codec processing on module '" << m_CSModule << "': " << e.what() << std::endl;
|
||||
m_TCReader.Close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -92,36 +116,38 @@ void CCodecStream::Task(void)
|
||||
STCPacket pack;
|
||||
|
||||
// any packet from transcoder
|
||||
if (m_TCReader->Receive(&pack, 5))
|
||||
if (m_TCReader.Receive(&pack, 5))
|
||||
{
|
||||
// update statistics
|
||||
double rt = pack.rt_timer.time(); // the round-trip time
|
||||
if ( m_RTMin == -1 )
|
||||
if (0 == m_RTCount)
|
||||
{
|
||||
m_RTMin = rt;
|
||||
m_RTMax = rt;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
m_RTMin = MIN(m_RTMin, rt);
|
||||
m_RTMax = MAX(m_RTMax, rt);
|
||||
|
||||
if (rt < m_RTMin)
|
||||
m_RTMin = rt;
|
||||
else if (rt > m_RTMax)
|
||||
m_RTMax = rt;
|
||||
}
|
||||
m_RTSum += rt;
|
||||
m_RTCount++;
|
||||
|
||||
if ( m_LocalQueue.empty() )
|
||||
if ( m_LocalQueue.IsEmpty() )
|
||||
{
|
||||
std::cout << "Unexpected transcoded packet received from transcoder" << std::endl;
|
||||
std::cout << "Unexpected transcoded packet received from transcoder: Module='" << pack.module << "' StreamID=" << std::hex << std::showbase << ntohs(pack.streamid) << std::endl;
|
||||
}
|
||||
else
|
||||
else if (m_IsOpen)
|
||||
{
|
||||
// pop the original packet
|
||||
auto Packet = m_LocalQueue.pop();
|
||||
auto Packet = m_LocalQueue.Pop();
|
||||
auto Frame = (CDvFramePacket *)Packet.get();
|
||||
|
||||
// do things look okay?
|
||||
if (pack.module != m_CSModule)
|
||||
std::cerr << "CodecStream '" << m_CSModule << "' received a transcoded packet from module '" << pack.module << "'" << std::dec << std::noshowbase << std::endl;
|
||||
if (pack.sequence != Frame->GetCodecPacket()->sequence)
|
||||
std::cerr << "Sequence mismatch: this voice frame=" << Frame->GetCodecPacket()->sequence << " returned transcoder packet=" << pack.sequence << std::endl;
|
||||
if (pack.streamid != Frame->GetCodecPacket()->streamid)
|
||||
@@ -137,31 +163,35 @@ void CCodecStream::Task(void)
|
||||
}
|
||||
|
||||
// and push it back to client
|
||||
m_PacketStream->Lock();
|
||||
m_PacketStream->push(Packet);
|
||||
m_PacketStream->Unlock();
|
||||
m_PacketStream->ReturnPacket(std::move(Packet));
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Transcoder packet received but CodecStream[" << m_CSModule << "] is closed: Module='" << pack.module << "' StreamID=" << std::hex << std::showbase << ntohs(pack.streamid) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// anything in our queue
|
||||
while ( !empty() )
|
||||
auto Packet = m_Queue.Pop();
|
||||
while (Packet)
|
||||
{
|
||||
// yes, pop it from queue
|
||||
auto Packet = pop();
|
||||
|
||||
// we need a CDvFramePacket pointer to access Frame stuff
|
||||
auto Frame = (CDvFramePacket *)Packet.get();
|
||||
|
||||
// push to our local queue so it can wait for the transcoder
|
||||
m_LocalQueue.push(Packet);
|
||||
if (m_IsOpen)
|
||||
{
|
||||
// update important stuff in Frame->m_TCPack for the transcoder
|
||||
// sets the packet counter, stream id, last_packet, module and start the trip timer
|
||||
Frame->SetTCParams(m_uiTotalPackets++);
|
||||
|
||||
// update important stuff in Frame->m_TCPack for the transcoder
|
||||
Frame->SetTCParams(m_uiTotalPackets++);
|
||||
// now send to transcoder
|
||||
m_TCWriter.Send(Frame->GetCodecPacket());
|
||||
|
||||
// now send to transcoder
|
||||
// this assume that thread pushing the Packet
|
||||
// have verified that the CodecStream is connected
|
||||
// and that the packet needs transcoding
|
||||
m_TCWriter.Send(Frame->GetCodecPacket());
|
||||
// push to our local queue where it can wait for the transcoder
|
||||
m_LocalQueue.Push(std::move(Packet));
|
||||
}
|
||||
|
||||
// get the next packet, if there is one
|
||||
Packet = m_Queue.Pop();
|
||||
}
|
||||
}
|
||||
+22
-7
@@ -18,19 +18,27 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <future>
|
||||
|
||||
#include "DVFramePacket.h"
|
||||
#include "UnixDgramSocket.h"
|
||||
#include "PacketQueue.h"
|
||||
#include "SafePacketQueue.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CPacketStream;
|
||||
|
||||
class CCodecStream : public CPacketQueue
|
||||
class CCodecStream
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CCodecStream(CPacketStream *packetstream, uint16_t streamid, ECodecType codectype, std::shared_ptr<CUnixDgramReader> reader);
|
||||
CCodecStream(CPacketStream *packetstream, char module);
|
||||
bool InitCodecStream();
|
||||
|
||||
void ResetStats(uint16_t streamid, ECodecType codectype);
|
||||
void ReportStats();
|
||||
|
||||
// destructor
|
||||
virtual ~CCodecStream();
|
||||
@@ -42,9 +50,14 @@ public:
|
||||
void Thread(void);
|
||||
void Task(void);
|
||||
|
||||
// pass-thru
|
||||
void Push(std::unique_ptr<CPacket> p) { m_Queue.Push(std::move(p)); }
|
||||
|
||||
protected:
|
||||
// initialization
|
||||
void InitCodecStream(void);
|
||||
// identity
|
||||
const char m_CSModule;
|
||||
// state
|
||||
std::atomic<bool> m_IsOpen;
|
||||
// data
|
||||
uint16_t m_uiStreamId;
|
||||
uint16_t m_uiPort;
|
||||
@@ -52,12 +65,14 @@ protected:
|
||||
ECodecType m_eCodecIn;
|
||||
|
||||
// sockets
|
||||
std::shared_ptr<CUnixDgramReader> m_TCReader;
|
||||
CUnixDgramReader m_TCReader;
|
||||
CUnixDgramWriter m_TCWriter;
|
||||
|
||||
// associated packet stream
|
||||
CPacketStream *m_PacketStream;
|
||||
CPacketQueue m_LocalQueue;
|
||||
|
||||
// queues
|
||||
CSafePacketQueue<std::unique_ptr<CPacket>> m_LocalQueue, m_Queue;
|
||||
|
||||
// thread
|
||||
std::atomic<bool> keep_running;
|
||||
|
||||
@@ -0,0 +1,988 @@
|
||||
/*
|
||||
* Copyright (c) 2023 by Thomas A. Early N7TAE
|
||||
*
|
||||
* 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 <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
#include <regex>
|
||||
|
||||
#include "Global.h"
|
||||
#include "CurlGet.h"
|
||||
|
||||
// ini file keywords
|
||||
#define JAUTOLINKMODULE "AutoLinkModule"
|
||||
#define JBLACKLISTPATH "BlacklistPath"
|
||||
#define JBRANDMEISTER "Brandmeister"
|
||||
#define JCALLSIGN "Callsign"
|
||||
#define JCOUNTRY "Country"
|
||||
#define JDCS "DCS"
|
||||
#define JDEFAULTID "DefaultId"
|
||||
#define JDEFAULTRXFREQ "DefaultRxFreq"
|
||||
#define JDEFAULTTXFREQ "DefaultTxFreq"
|
||||
#define JDESCRIPTION "Description"
|
||||
#define JDEXTRA "DExtra"
|
||||
#define JDMRIDDB "DMR ID DB"
|
||||
#define JDMRPLUS "DMRPlus"
|
||||
#define JDPLUS "DPlus"
|
||||
#define JENABLE "Enable"
|
||||
#define JFILES "Files"
|
||||
#define JFILEPATH "FilePath"
|
||||
#define JG3 "G3"
|
||||
#define JG3TERMINALPATH "G3TerminalPath"
|
||||
#define JINTERLINKPATH "InterlinkPath"
|
||||
#define JIPADDRESS "IPAddress"
|
||||
#define JIPADDRESSES "IP Addresses"
|
||||
#define JIPV4BINDING "IPv4Binding"
|
||||
#define JIPV4EXTERNAL "IPv4External"
|
||||
#define JIPV6BINDING "IPv6Binding"
|
||||
#define JIPV6EXTERNAL "IPv6External"
|
||||
#define JJSONPATH "JsonPath"
|
||||
#define JM17 "M17"
|
||||
#define JMMDVM "MMDVM"
|
||||
#define JMODE "Mode"
|
||||
#define JMODULE "Module"
|
||||
#define JMODULES "Modules"
|
||||
#define JNAMES "Names"
|
||||
#define JNXDNIDDB "NXDN ID DB"
|
||||
#define JNXDN "NXDN"
|
||||
#define JP25 "P25"
|
||||
#define JPIDPATH "PidPath"
|
||||
#define JPORT "Port"
|
||||
#define JREFLECTORID "ReflectorID"
|
||||
#define JREFRESHMIN "RefreshMin"
|
||||
#define JREGISTRATIONDESCRIPTION "RegistrationDescription"
|
||||
#define JREGISTRATIONID "RegistrationID"
|
||||
#define JREGISTRATIONNAME "RegistrationName"
|
||||
#define JRXPORT "RxPort"
|
||||
#define JSPONSOR "Sponsor"
|
||||
#define JSYSOPEMAIL "SysopEmail"
|
||||
#define JTRANSCODED "Transcoded"
|
||||
#define JTRANSCODER "Transcoder"
|
||||
#define JTXPORT "TxPort"
|
||||
#define JURF "URF"
|
||||
#define JURL "URL"
|
||||
#define JUSRP "USRP"
|
||||
#define JWHITELISTPATH "WhitelistPath"
|
||||
#define JXMLPATH "XmlPath"
|
||||
#define JYSF "YSF"
|
||||
#define JYSFTXRXDB "YSF TX/RX DB"
|
||||
|
||||
static inline void split(const std::string &s, char delim, std::vector<std::string> &v)
|
||||
{
|
||||
std::istringstream iss(s);
|
||||
std::string item;
|
||||
while (std::getline(iss, item, delim))
|
||||
v.push_back(item);
|
||||
}
|
||||
|
||||
// trim from start (in place)
|
||||
static inline void ltrim(std::string &s) {
|
||||
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) {
|
||||
return !std::isspace(ch);
|
||||
}));
|
||||
}
|
||||
|
||||
// trim from end (in place)
|
||||
static inline void rtrim(std::string &s) {
|
||||
s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) {
|
||||
return !std::isspace(ch);
|
||||
}).base(), s.end());
|
||||
}
|
||||
|
||||
// trim from both ends (in place)
|
||||
static inline void trim(std::string &s) {
|
||||
ltrim(s);
|
||||
rtrim(s);
|
||||
}
|
||||
|
||||
CConfigure::CConfigure()
|
||||
{
|
||||
IPv4RegEx = std::regex("^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3,3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9]){1,1}$", std::regex::extended);
|
||||
IPv6RegEx = std::regex("^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}(:[0-9a-fA-F]{1,4}){1,1}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|([0-9a-fA-F]{1,4}:){1,1}(:[0-9a-fA-F]{1,4}){1,6}|:((:[0-9a-fA-F]{1,4}){1,7}|:))$", std::regex::extended);
|
||||
}
|
||||
|
||||
bool CConfigure::ReadData(const std::string &path)
|
||||
// returns true on failure
|
||||
{
|
||||
bool rval = false;
|
||||
ESection section = ESection::none;
|
||||
counter = 0;
|
||||
SJsonKeys::DB *pdb;
|
||||
|
||||
//data.ysfalmodule = 0;
|
||||
//data.DPlusPort = data.DCSPort = data.DExtraPort = data.BMPort = data.DMRPlusPort = 0;
|
||||
std::ifstream cfgfile(path.c_str(), std::ifstream::in);
|
||||
if (! cfgfile.is_open()) {
|
||||
std::cerr << "ERROR: '" << path << "' was not found!" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string ipv4, ipv6;
|
||||
|
||||
{
|
||||
CCurlGet curl;
|
||||
std::stringstream ss;
|
||||
if (CURLE_OK == curl.GetURL("https://ipv4.icanhazip.com", ss))
|
||||
{
|
||||
ipv4.assign(ss.str());
|
||||
trim(ipv4);
|
||||
}
|
||||
ss.str(std::string());
|
||||
if (CURLE_OK == curl.GetURL("https://ipv6.icanhazip.com", ss))
|
||||
{
|
||||
ipv6.assign(ss.str());
|
||||
trim(ipv6);
|
||||
}
|
||||
}
|
||||
|
||||
std::string line;
|
||||
while (std::getline(cfgfile, line))
|
||||
{
|
||||
counter++;
|
||||
trim(line);
|
||||
if (3 > line.size())
|
||||
continue; // can't be anything
|
||||
if ('#' == line.at(0))
|
||||
continue; // skip comments
|
||||
|
||||
// check for next section
|
||||
if ('[' == line.at(0))
|
||||
{
|
||||
std::string hname(line.substr(1));
|
||||
auto pos = hname.find(']');
|
||||
if (std::string::npos != pos)
|
||||
hname.resize(pos);
|
||||
section = ESection::none;
|
||||
if (0 == hname.compare(JNAMES))
|
||||
section = ESection::names;
|
||||
else if (0 == hname.compare(JIPADDRESSES))
|
||||
section = ESection::ip;
|
||||
else if (0 == hname.compare(JMODULES))
|
||||
section = ESection::modules;
|
||||
else if (0 == hname.compare(JDPLUS))
|
||||
section = ESection::dplus;
|
||||
else if (0 == hname.compare(JDEXTRA))
|
||||
section = ESection::dextra;
|
||||
else if (0 == hname.compare(JG3))
|
||||
section = ESection::g3;
|
||||
else if (0 == hname.compare(JDMRPLUS))
|
||||
section = ESection::dmrplus;
|
||||
else if (0 == hname.compare(JMMDVM))
|
||||
section = ESection::mmdvm;
|
||||
else if (0 == hname.compare(JNXDN))
|
||||
section = ESection::nxdn;
|
||||
else if (0 == hname.compare(JBRANDMEISTER))
|
||||
section = ESection::bm;
|
||||
else if (0 == hname.compare(JYSF))
|
||||
section = ESection::ysf;
|
||||
else if (0 == hname.compare(JDCS))
|
||||
section = ESection::dcs;
|
||||
else if (0 == hname.compare(JP25))
|
||||
section = ESection::p25;
|
||||
else if (0 == hname.compare(JM17))
|
||||
section = ESection::m17;
|
||||
else if (0 == hname.compare(JUSRP))
|
||||
section = ESection::usrp;
|
||||
else if (0 == hname.compare(JURF))
|
||||
section = ESection::urf;
|
||||
else if (0 == hname.compare(JDMRIDDB))
|
||||
section = ESection::dmrid;
|
||||
else if (0 == hname.compare(JNXDNIDDB))
|
||||
section = ESection::nxdnid;
|
||||
else if (0 == hname.compare(JYSFTXRXDB))
|
||||
section = ESection::ysffreq;
|
||||
else if (0 == hname.compare(JFILES))
|
||||
section = ESection::files;
|
||||
else
|
||||
{
|
||||
std::cerr << "WARNING: unknown ini file section: " << line << std::endl;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<std::string> tokens;
|
||||
split(line, '=', tokens);
|
||||
// check value for end-of-line comment
|
||||
if (2 > tokens.size())
|
||||
{
|
||||
std::cout << "WARNING: line #" << counter << ": '" << line << "' does not contain an equal sign, skipping" << std::endl;
|
||||
continue;
|
||||
}
|
||||
auto pos = tokens[1].find('#');
|
||||
if (std::string::npos != pos)
|
||||
{
|
||||
tokens[1].assign(tokens[1].substr(0, pos));
|
||||
rtrim(tokens[1]); // whitespace between the value and the end-of-line comment
|
||||
}
|
||||
// trim whitespace from around the '='
|
||||
rtrim(tokens[0]);
|
||||
ltrim(tokens[1]);
|
||||
const std::string key(tokens[0]);
|
||||
const std::string value(tokens[1]);
|
||||
if (key.empty() || value.empty())
|
||||
{
|
||||
std::cout << "WARNING: line #" << counter << ": missing key or value: '" << line << "'" << std::endl;
|
||||
continue;
|
||||
}
|
||||
switch (section)
|
||||
{
|
||||
case ESection::names:
|
||||
if (0 == key.compare(JCALLSIGN))
|
||||
data[g_Keys.names.callsign] = value;
|
||||
else if (0 == key.compare(JSYSOPEMAIL))
|
||||
data[g_Keys.names.email] = value;
|
||||
else if (0 == key.compare(JCOUNTRY))
|
||||
data[g_Keys.names.country] = value.substr(0,2);
|
||||
else if (0 == key.compare(JSPONSOR))
|
||||
data[g_Keys.names.sponsor] = value;
|
||||
else
|
||||
badParam(key);
|
||||
break;
|
||||
case ESection::ip:
|
||||
if (0 == key.compare(JIPV4BINDING))
|
||||
{
|
||||
data[g_Keys.ip.ipv4bind] = value;
|
||||
}
|
||||
else if (0 == key.compare(JIPV6BINDING))
|
||||
{
|
||||
data[g_Keys.ip.ipv6bind] = value;
|
||||
}
|
||||
else if (0 == key.compare(JIPV4EXTERNAL))
|
||||
{
|
||||
data[g_Keys.ip.ipv4address] = value;
|
||||
}
|
||||
else if (0 == key.compare(JIPV6EXTERNAL))
|
||||
{
|
||||
data[g_Keys.ip.ipv6address] = value;
|
||||
}
|
||||
else if (0 == key.compare(JTRANSCODER))
|
||||
{
|
||||
if (value.compare("local"))
|
||||
{
|
||||
std::cout << "WARNING: Line #" << counter << ": malformed transcoder address, '" << value << "', resetting..." << std::endl;
|
||||
}
|
||||
data[g_Keys.ip.transcoder] = "local";
|
||||
}
|
||||
else
|
||||
badParam(key);
|
||||
break;
|
||||
case ESection::modules:
|
||||
if (0 == key.compare(JMODULES))
|
||||
{
|
||||
std::string m(value);
|
||||
if (checkModules(m))
|
||||
{
|
||||
std::cerr << "ERROR: line #" << counter << ": no letters found in Modules: '" << m << "'" << std::endl;
|
||||
rval = true;
|
||||
} else
|
||||
data[g_Keys.modules.modules] = m;
|
||||
}
|
||||
else if (0 == key.compare(JTRANSCODED))
|
||||
{
|
||||
std::string m(value);
|
||||
if (checkModules(m))
|
||||
{
|
||||
std::cerr << "ERROR: line #" << counter << ": no letters found in Transcoded: '" << m << "'" << std::endl;
|
||||
rval = true;
|
||||
} else
|
||||
data[g_Keys.modules.tcmodules] = m;
|
||||
}
|
||||
else if (0 == key.compare(0, 11, "Description"))
|
||||
{
|
||||
if (12 == key.size() && isupper(key[11]))
|
||||
data[key] = value;
|
||||
else
|
||||
badParam(key);
|
||||
}
|
||||
else
|
||||
badParam(key);
|
||||
break;
|
||||
case ESection::bm:
|
||||
if (0 == key.compare(JPORT))
|
||||
data[g_Keys.bm.port] = getUnsigned(value, "Brandmeister Port", 1024, 65535, 10002);
|
||||
else if (0 == key.compare(JENABLE))
|
||||
data[g_Keys.bm.enable] = IS_TRUE(value[0]);
|
||||
else
|
||||
badParam(key);
|
||||
break;
|
||||
case ESection::dcs:
|
||||
if (0 == key.compare(JPORT))
|
||||
data[g_Keys.dcs.port] = getUnsigned(value, "DCS Port", 1024, 65535, 30051);
|
||||
else
|
||||
badParam(key);
|
||||
break;
|
||||
case ESection::dextra:
|
||||
if (0 == key.compare(JPORT))
|
||||
data[g_Keys.dextra.port] = getUnsigned(value, "DExtra Port", 1024, 65535, 30001);
|
||||
else
|
||||
badParam(key);
|
||||
break;
|
||||
case ESection::g3:
|
||||
if (0 == key.compare(JENABLE))
|
||||
data[g_Keys.g3.enable] = IS_TRUE(value[0]);
|
||||
else
|
||||
badParam(key);
|
||||
break;
|
||||
case ESection::dmrplus:
|
||||
if (0 == key.compare(JPORT))
|
||||
data[g_Keys.dmrplus.port] = getUnsigned(value, "DMRPlus Port", 1024, 65535, 8880);
|
||||
else
|
||||
badParam(key);
|
||||
break;
|
||||
case ESection::dplus:
|
||||
if (0 == key.compare(JPORT))
|
||||
data[g_Keys.dplus.port] = getUnsigned(value, "DPlus Port", 1024, 65535, 20001);
|
||||
else
|
||||
badParam(key);
|
||||
break;
|
||||
case ESection::m17:
|
||||
if (0 == key.compare(JPORT))
|
||||
data[g_Keys.m17.port] = getUnsigned(value, "M17 Port", 1024, 65535, 17000);
|
||||
else
|
||||
badParam(key);
|
||||
break;
|
||||
case ESection::mmdvm:
|
||||
if (0 == key.compare(JPORT))
|
||||
data[g_Keys.mmdvm.port] = getUnsigned(value, "MMDVM Port", 1024, 65535, 62030);
|
||||
else if (0 == key.compare(JDEFAULTID))
|
||||
data[g_Keys.mmdvm.defaultid] = getUnsigned(value, "MMDVM DefaultID", 0, 9999999, 0);
|
||||
else
|
||||
badParam(key);
|
||||
break;
|
||||
case ESection::nxdn:
|
||||
if (0 == key.compare(JPORT))
|
||||
data[g_Keys.nxdn.port] = getUnsigned(value, "NDXN Port", 1024, 65535, 41400);
|
||||
else if (0 == key.compare(JAUTOLINKMODULE))
|
||||
setAutolink(JNXDN, g_Keys.nxdn.autolinkmod, value);
|
||||
else if (0 == key.compare(JREFLECTORID))
|
||||
data[g_Keys.nxdn.reflectorid] = getUnsigned(value, "NXDN ReflectorID", 0, 65535, 0);
|
||||
else
|
||||
badParam(key);
|
||||
break;
|
||||
case ESection::p25:
|
||||
if (0 == key.compare(JPORT))
|
||||
data[g_Keys.p25.port] = getUnsigned(value, "P25 Port", 1024, 65535, 41000);
|
||||
else if (0 == key.compare(JAUTOLINKMODULE))
|
||||
setAutolink(JP25, g_Keys.p25.autolinkmod, value);
|
||||
else if (0 == key.compare(JREFLECTORID))
|
||||
data[g_Keys.p25.reflectorid] = getUnsigned(value, "P25 ReflectorID", 0, 16777215, 0);
|
||||
else
|
||||
badParam(key);
|
||||
break;
|
||||
case ESection::urf:
|
||||
if (0 == key.compare(JPORT))
|
||||
data[g_Keys.urf.port] = getUnsigned(value, "URF Port", 1024, 65535, 10017);
|
||||
else
|
||||
badParam(key);
|
||||
break;
|
||||
case ESection::usrp:
|
||||
if (0 == key.compare(JENABLE))
|
||||
data[g_Keys.usrp.enable] = IS_TRUE(value[0]);
|
||||
else if (0 == key.compare(JIPADDRESS))
|
||||
data[g_Keys.usrp.ip] = value;
|
||||
else if (0 == key.compare(JTXPORT))
|
||||
data[g_Keys.usrp.txport] = getUnsigned(value, "USRP TxPort", 1024, 65535, 32000);
|
||||
else if (0 == key.compare(JRXPORT))
|
||||
data[g_Keys.usrp.rxport] = getUnsigned(value, "USRP RxPort", 1024, 65535, 34000);
|
||||
else if (0 == key.compare(JMODULE))
|
||||
data[g_Keys.usrp.module] = value.substr(0, 1);
|
||||
else if (0 == key.compare(JCALLSIGN))
|
||||
data[g_Keys.usrp.callsign] = value;
|
||||
else if (0 == key.compare(JFILEPATH))
|
||||
data[g_Keys.usrp.filepath] = value;
|
||||
else
|
||||
badParam(key);
|
||||
break;
|
||||
case ESection::ysf:
|
||||
if (0 == key.compare(JPORT))
|
||||
data[g_Keys.ysf.port] = getUnsigned(value, "YSF Port", 1024, 65535, 42000);
|
||||
else if (0 == key.compare(JAUTOLINKMODULE))
|
||||
setAutolink(JYSF, g_Keys.ysf.autolinkmod, value);
|
||||
else if (0 == key.compare(JDEFAULTTXFREQ))
|
||||
data[g_Keys.ysf.defaulttxfreq] = getUnsigned(value, "YSF DefaultTxFreq", 40000000, 2600000000, 439000000);
|
||||
else if (0 == key.compare(JDEFAULTRXFREQ))
|
||||
data[g_Keys.ysf.defaultrxfreq] = getUnsigned(value, "YSF DefaultRxFreq", 40000000, 2600000000, 439000000);
|
||||
else if (0 == key.compare(JREGISTRATIONID))
|
||||
data[g_Keys.ysf.ysfreflectordb.id] = getUnsigned(value, "YSF RegistrationID", 0, 9999999, 0);
|
||||
else if (0 == key.compare(JREGISTRATIONNAME))
|
||||
{
|
||||
std::string name(value);
|
||||
if (name.size() > 13) name.resize(13);
|
||||
data[g_Keys.ysf.ysfreflectordb.name] = name;
|
||||
}
|
||||
else if (0 == key.compare(JREGISTRATIONDESCRIPTION))
|
||||
{
|
||||
std::string desc(value);
|
||||
if (desc.size() > 16) desc.resize(16);
|
||||
data[g_Keys.ysf.ysfreflectordb.description] = desc;
|
||||
}
|
||||
else
|
||||
badParam(key);
|
||||
break;
|
||||
case ESection::dmrid:
|
||||
case ESection::nxdnid:
|
||||
case ESection::ysffreq:
|
||||
switch (section)
|
||||
{
|
||||
case ESection::dmrid: pdb = &g_Keys.dmriddb; break;
|
||||
case ESection::nxdnid: pdb = &g_Keys.nxdniddb; break;
|
||||
case ESection::ysffreq: pdb = &g_Keys.ysftxrxdb; break;
|
||||
}
|
||||
if (0 == key.compare(JURL))
|
||||
data[pdb->url] = value;
|
||||
else if (0 == key.compare(JMODE))
|
||||
{
|
||||
if ((0==value.compare("file")) || (0==value.compare("http")) || (0==value.compare("both")))
|
||||
data[pdb->mode] = value;
|
||||
else
|
||||
{
|
||||
std::cout << "WARNING: line #" << counter << ": Mode, '" << value << "' not recognized. Setting to 'http'" << std::endl;
|
||||
data[pdb->mode] = "http";
|
||||
}
|
||||
}
|
||||
else if (0 == key.compare(JREFRESHMIN))
|
||||
data[pdb->refreshmin] = getUnsigned(value, JREFRESHMIN, 15, 14400, 180);
|
||||
else if (0 == key.compare(JFILEPATH))
|
||||
data[pdb->filepath] = value;
|
||||
else
|
||||
badParam(key);
|
||||
break;
|
||||
case ESection::files:
|
||||
if (0 == key.compare(JPIDPATH))
|
||||
data[g_Keys.files.pid] = value;
|
||||
else if (0 == key.compare(JXMLPATH))
|
||||
data[g_Keys.files.xml] = value;
|
||||
else if (0 == key.compare(JJSONPATH))
|
||||
data[g_Keys.files.json] = value;
|
||||
else if (0 == key.compare(JWHITELISTPATH))
|
||||
data[g_Keys.files.white] = value;
|
||||
else if (0 == key.compare(JBLACKLISTPATH))
|
||||
data[g_Keys.files.black] = value;
|
||||
else if (0 == key.compare(JINTERLINKPATH))
|
||||
data[g_Keys.files.interlink] = value;
|
||||
else if (0 == key.compare(JG3TERMINALPATH))
|
||||
data[g_Keys.files.terminal] = value;
|
||||
else
|
||||
badParam(key);
|
||||
break;
|
||||
default:
|
||||
std::cout << "WARNING: parameter '" << line << "' defined befor any [section]" << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
cfgfile.close();
|
||||
|
||||
////////////////////////////// check the input
|
||||
// Names section
|
||||
if (isDefined(ErrorLevel::fatal, JNAMES, JCALLSIGN, g_Keys.names.callsign, rval))
|
||||
{
|
||||
const auto cs = data[g_Keys.names.callsign].get<std::string>();
|
||||
auto RefRegEx = std::regex("^URF([A-Z0-9]){3,3}$", std::regex::extended);
|
||||
if (! std::regex_match(cs, RefRegEx))
|
||||
{
|
||||
std::cerr << "ERROR: [" << JNAMES << ']' << JCALLSIGN << " '" << cs << "' is malformed" << std::endl;
|
||||
rval = true;
|
||||
}
|
||||
}
|
||||
|
||||
isDefined(ErrorLevel::mild, JNAMES, JSYSOPEMAIL, g_Keys.names.email, rval);
|
||||
isDefined(ErrorLevel::mild, JNAMES, JCOUNTRY, g_Keys.names.country, rval);
|
||||
isDefined(ErrorLevel::mild, JNAMES, JSPONSOR, g_Keys.names.sponsor, rval);
|
||||
|
||||
// IP Address section
|
||||
// ipv4 bind and external
|
||||
if (isDefined(ErrorLevel::fatal, JIPADDRESSES, JIPV4BINDING, g_Keys.ip.ipv4bind, rval))
|
||||
{
|
||||
if (std::regex_match(data[g_Keys.ip.ipv4bind].get<std::string>(), IPv4RegEx))
|
||||
{
|
||||
if (data.contains(g_Keys.ip.ipv4address))
|
||||
{
|
||||
auto v4 = data[g_Keys.ip.ipv4address].get<std::string>();
|
||||
if (std::regex_match(v4, IPv4RegEx))
|
||||
{
|
||||
if (ipv4.compare(v4))
|
||||
std::cout << "WARNING: specified IPv4 external address, " << v4 << ", is different than detected address, " << ipv4 << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "ERROR: specifed IPv4 external address, " << v4 << ", is malformed" << std::endl;
|
||||
rval = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// make sure curl worked!
|
||||
if (std::regex_match(ipv4, IPv4RegEx))
|
||||
data[g_Keys.ip.ipv4address] = ipv4;
|
||||
else
|
||||
{
|
||||
std::cerr << "ERROR: could not detect IPv4 address at this time" << std::endl;
|
||||
rval = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "ERROR: IPv4 binding address, " << data[g_Keys.ip.ipv4address].get<std::string>() << ", is malformed" << std::endl;
|
||||
rval = true;
|
||||
}
|
||||
}
|
||||
|
||||
// ipv6 bind and external
|
||||
if (data.contains(g_Keys.ip.ipv6bind))
|
||||
{
|
||||
if (std::regex_match(data[g_Keys.ip.ipv6bind].get<std::string>(), IPv6RegEx))
|
||||
{
|
||||
if (data.contains(g_Keys.ip.ipv6address))
|
||||
{
|
||||
auto v6 = data[g_Keys.ip.ipv6address].get<std::string>();
|
||||
if (std::regex_match(v6, IPv6RegEx))
|
||||
{
|
||||
if (ipv6.compare(v6))
|
||||
std::cout << "WARNING: specified IPv6 external address [" << v6 << "], is different than detected address [" << ipv6 << ']' << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "ERROR: the specifed IPv6 address [" << v6 << "] is malformed" << std::endl;
|
||||
rval = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// make sure curl worked!
|
||||
if (std::regex_match(ipv6, IPv6RegEx))
|
||||
data[g_Keys.ip.ipv6address] = ipv6;
|
||||
else
|
||||
{
|
||||
std::cerr << "ERROR: could not detect IPv6 address at this time" << std::endl;
|
||||
rval = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "ERROR: IPv6 binding address, " << data[g_Keys.ip.ipv6address].get<std::string>() << ", is malformed" << std::endl;
|
||||
rval = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
data[g_Keys.ip.ipv6bind] = nullptr;
|
||||
data[g_Keys.ip.ipv6address] = nullptr;
|
||||
}
|
||||
|
||||
// Modules section
|
||||
if (isDefined(ErrorLevel::fatal, JMODULES, JMODULES, g_Keys.modules.modules, rval))
|
||||
{
|
||||
const auto mods(data[g_Keys.modules.modules].get<std::string>());
|
||||
if (data.contains(g_Keys.modules.tcmodules))
|
||||
{
|
||||
const auto tcmods(data[g_Keys.modules.tcmodules].get<std::string>());
|
||||
|
||||
// how many transcoded modules
|
||||
auto size = tcmods.size();
|
||||
if (3 != size && 1 != size)
|
||||
std::cout << "WARNING: [" << JMODULES << ']' << JTRANSCODED << " doesn't define one (or three) modules" << std::endl;
|
||||
|
||||
// make sure each transcoded module is configured
|
||||
for (auto c : tcmods)
|
||||
{
|
||||
if (std::string::npos == mods.find(c))
|
||||
{
|
||||
std::cerr << "ERROR: transcoded module '" << c << "' not found in defined modules" << std::endl;
|
||||
rval = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
data[g_Keys.modules.tcmodules] = nullptr;
|
||||
|
||||
// finally, check the module descriptions
|
||||
for (unsigned i=0; i<26; i++)
|
||||
{
|
||||
if (std::string::npos == mods.find('A'+i))
|
||||
{
|
||||
if (data.contains(g_Keys.modules.descriptor[i]))
|
||||
{
|
||||
std::cout << "WARNING: " << g_Keys.modules.descriptor[i] << " defined for an unconfigured module. Deleting..." << std::endl;
|
||||
data.erase(g_Keys.modules.descriptor[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! data.contains(g_Keys.modules.descriptor[i]))
|
||||
{
|
||||
std::string value("Module ");
|
||||
value.append(1, 'A'+i);
|
||||
std::cout << "WARNING: " << g_Keys.modules.descriptor[i] << " not found. Setting to " << value << std::endl;
|
||||
data[g_Keys.modules.descriptor[i]] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// "simple" protocols with only a Port
|
||||
isDefined(ErrorLevel::fatal, JDCS, JPORT, g_Keys.dcs.port, rval);
|
||||
isDefined(ErrorLevel::fatal, JDEXTRA, JPORT, g_Keys.dextra.port, rval);
|
||||
isDefined(ErrorLevel::fatal, JDMRPLUS, JPORT, g_Keys.dmrplus.port, rval);
|
||||
isDefined(ErrorLevel::fatal, JDPLUS, JPORT, g_Keys.dplus.port, rval);
|
||||
isDefined(ErrorLevel::fatal, JM17, JPORT, g_Keys.m17.port, rval);
|
||||
isDefined(ErrorLevel::fatal, JURF, JPORT, g_Keys.urf.port, rval);
|
||||
|
||||
// BM
|
||||
if (isDefined(ErrorLevel::fatal, JBRANDMEISTER, JENABLE, g_Keys.bm.enable, rval))
|
||||
{
|
||||
if (GetBoolean(g_Keys.bm.enable))
|
||||
{
|
||||
isDefined(ErrorLevel::fatal, JBRANDMEISTER, JPORT, g_Keys.bm.port, rval);
|
||||
}
|
||||
}
|
||||
|
||||
// G3
|
||||
isDefined(ErrorLevel::fatal, JG3, JENABLE, g_Keys.g3.enable, rval);
|
||||
|
||||
// MMDVM
|
||||
isDefined(ErrorLevel::fatal, JMMDVM, JPORT, g_Keys.mmdvm.port, rval);
|
||||
isDefined(ErrorLevel::fatal, JMMDVM, JDEFAULTID, g_Keys.mmdvm.defaultid, rval);
|
||||
|
||||
// NXDN
|
||||
isDefined(ErrorLevel::fatal, JNXDN, JPORT, g_Keys.nxdn.port, rval);
|
||||
checkAutoLink(JNXDN, JAUTOLINKMODULE, g_Keys.nxdn.autolinkmod, rval);
|
||||
isDefined(ErrorLevel::fatal, JNXDN, JREFLECTORID, g_Keys.nxdn.reflectorid, rval);
|
||||
|
||||
// P25
|
||||
isDefined(ErrorLevel::fatal, JP25, JPORT, g_Keys.p25.port, rval);
|
||||
checkAutoLink(JP25, JAUTOLINKMODULE, g_Keys.p25.autolinkmod, rval);
|
||||
isDefined(ErrorLevel::fatal, JP25, JREFLECTORID, g_Keys.p25.reflectorid, rval);
|
||||
|
||||
// USRP
|
||||
if (isDefined(ErrorLevel::fatal, JUSRP, JENABLE, g_Keys.usrp.enable, rval))
|
||||
{
|
||||
if (GetBoolean(g_Keys.usrp.enable))
|
||||
{
|
||||
if (IsString(g_Keys.modules.tcmodules))
|
||||
{
|
||||
if (isDefined(ErrorLevel::fatal, JUSRP, JMODULE, g_Keys.usrp.module, rval))
|
||||
{
|
||||
if (std::string::npos == GetString(g_Keys.modules.tcmodules).find(GetString(g_Keys.usrp.module).at(0)))
|
||||
{
|
||||
std::cerr << "ERROR: [" << JUSRP << ']' << JMODULE << " is not a transcoded module" << std::endl;
|
||||
rval = true;
|
||||
}
|
||||
}
|
||||
if (isDefined(ErrorLevel::fatal, JUSRP, JIPADDRESS, g_Keys.usrp.ip, rval))
|
||||
{
|
||||
// check for syntax
|
||||
if (! std::regex_match(data[g_Keys.usrp.ip].get<std::string>(), IPv4RegEx))
|
||||
{
|
||||
std::cerr << "ERROR: [" << JUSRP << ']' << JIPADDRESS " '" << data[g_Keys.usrp.ip] << "' is malformed" << std::endl;
|
||||
rval = true;
|
||||
}
|
||||
}
|
||||
isDefined(ErrorLevel::fatal, JUSRP, JTXPORT, g_Keys.usrp.txport, rval);
|
||||
isDefined(ErrorLevel::fatal, JUSRP, JRXPORT, g_Keys.usrp.rxport, rval);
|
||||
isDefined(ErrorLevel::fatal, JUSRP, JCALLSIGN, g_Keys.usrp.callsign, rval);
|
||||
//if (isDefined(ErrorLevel::fatal, JUSRP, JFILEPATH, g_Keys.usrp.filepath, rval))
|
||||
if (data.contains(g_Keys.usrp.filepath))
|
||||
checkFile(JUSRP, JFILEPATH, data[g_Keys.usrp.filepath]);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "ERROR: " << JUSRP << " requires a transoder" << std::endl;
|
||||
rval = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// YSF
|
||||
isDefined(ErrorLevel::fatal, JYSF, JPORT, g_Keys.ysf.port, rval);
|
||||
checkAutoLink(JYSF, JAUTOLINKMODULE, g_Keys.ysf.autolinkmod, rval);
|
||||
isDefined(ErrorLevel::fatal, JYSF, JDEFAULTRXFREQ, g_Keys.ysf.defaultrxfreq, rval);
|
||||
isDefined(ErrorLevel::fatal, JYSF, JDEFAULTTXFREQ, g_Keys.ysf.defaulttxfreq, rval);
|
||||
isDefined(ErrorLevel::mild, JYSF, JREGISTRATIONID, g_Keys.ysf.ysfreflectordb.id, rval);
|
||||
isDefined(ErrorLevel::mild, JYSF, JREGISTRATIONNAME, g_Keys.ysf.ysfreflectordb.name, rval);
|
||||
isDefined(ErrorLevel::mild, JYSF, JREGISTRATIONDESCRIPTION, g_Keys.ysf.ysfreflectordb.description, rval);
|
||||
|
||||
// Databases
|
||||
std::list<std::pair<const std::string, const struct SJsonKeys::DB *>> dbs = {
|
||||
{ JDMRIDDB, &g_Keys.dmriddb },
|
||||
{ JNXDNIDDB, &g_Keys.nxdniddb },
|
||||
{ JYSFTXRXDB, &g_Keys.ysftxrxdb }
|
||||
};
|
||||
for ( auto &item : dbs )
|
||||
{
|
||||
if (isDefined(ErrorLevel::fatal, item.first, JMODE, item.second->mode, rval))
|
||||
{
|
||||
if (ERefreshType::file != GetRefreshType(item.second->mode))
|
||||
{
|
||||
isDefined(ErrorLevel::fatal, item.first, JURL, item.second->url, rval);
|
||||
isDefined(ErrorLevel::fatal, item.first, JREFRESHMIN, item.second->refreshmin, rval);
|
||||
}
|
||||
if (ERefreshType::http != GetRefreshType(item.second->mode))
|
||||
{
|
||||
if (isDefined(ErrorLevel::fatal, item.first, JFILEPATH, item.second->filepath, rval))
|
||||
checkFile(item.first, JFILEPATH, data[item.second->filepath]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Other files
|
||||
isDefined(ErrorLevel::fatal, JFILES, JPIDPATH, g_Keys.files.pid, rval);
|
||||
isDefined(ErrorLevel::fatal, JFILES, JXMLPATH, g_Keys.files.xml, rval);
|
||||
if (isDefined(ErrorLevel::fatal, JFILES, JWHITELISTPATH, g_Keys.files.white, rval))
|
||||
checkFile(JFILES, JWHITELISTPATH, data[g_Keys.files.white]);
|
||||
if (isDefined(ErrorLevel::fatal, JFILES, JBLACKLISTPATH, g_Keys.files.black, rval))
|
||||
checkFile(JFILES, JBLACKLISTPATH, data[g_Keys.files.black]);
|
||||
if (isDefined(ErrorLevel::fatal, JFILES, JINTERLINKPATH, g_Keys.files.interlink, rval))
|
||||
checkFile(JFILES, JINTERLINKPATH, data[g_Keys.files.interlink]);
|
||||
if (data.contains(g_Keys.g3.enable) && GetBoolean(g_Keys.g3.enable))
|
||||
{
|
||||
if (isDefined(ErrorLevel::fatal, JFILES, JG3TERMINALPATH, g_Keys.files.terminal, rval))
|
||||
checkFile(JFILES, JG3TERMINALPATH, data[g_Keys.files.terminal]);
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
bool CConfigure::isDefined(ErrorLevel level, const std::string §ion, const std::string &pname, const std::string &key, bool &rval)
|
||||
{
|
||||
if (data.contains(key))
|
||||
return true;
|
||||
|
||||
if (ErrorLevel::mild == level)
|
||||
{
|
||||
std::cout << "WARNING: [" << section << ']' << pname << " is not defined" << std::endl;
|
||||
data[key] = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "ERROR: [" << section << ']' << pname << " is not defined" << std::endl;
|
||||
rval = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CConfigure::checkAutoLink(const std::string §ion, const std::string &pname, const std::string &key, bool &rval)
|
||||
{
|
||||
if (data.contains(key))
|
||||
{
|
||||
auto ismods = data.contains(g_Keys.modules.modules);
|
||||
const auto mods(ismods ? data[g_Keys.modules.modules].get<std::string>() : "");
|
||||
const auto c = data[key].get<std::string>().at(0);
|
||||
if (std::string::npos == mods.find(c))
|
||||
{
|
||||
std::cerr << "ERROR: [" << section << ']' << pname << " module '" << c << "' not a configured module" << std::endl;
|
||||
rval = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
data[key] = nullptr;
|
||||
}
|
||||
|
||||
std::string CConfigure::getDataRefreshType(ERefreshType type) const
|
||||
{
|
||||
if (ERefreshType::both == type)
|
||||
return std::string("both");
|
||||
else if (ERefreshType::file == type)
|
||||
return std::string("file");
|
||||
else
|
||||
return std::string("http");
|
||||
}
|
||||
|
||||
unsigned CConfigure::getUnsigned(const std::string &valuestr, const std::string &label, unsigned min, unsigned max, unsigned def) const
|
||||
{
|
||||
auto i = unsigned(std::stoul(valuestr.c_str()));
|
||||
if ( i < min || i > max )
|
||||
{
|
||||
std::cout << "WARNING: line #" << counter << ": " << label << " is out of range. Reset to " << def << std::endl;
|
||||
i = def;
|
||||
}
|
||||
return (unsigned)i;
|
||||
}
|
||||
|
||||
void CConfigure::badParam(const std::string &key) const
|
||||
{
|
||||
std::cout << "WARNING: line #" << counter << ": Unexpected parameter: '" << key << "'" << std::endl;
|
||||
}
|
||||
|
||||
bool CConfigure::checkModules(std::string &m) const
|
||||
{
|
||||
bool rval = false; // return true on error
|
||||
for(unsigned i=0; i<m.size(); i++)
|
||||
if (islower(m[i]))
|
||||
m[i] = toupper(m[i]);
|
||||
|
||||
const std::string all("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
||||
std::string found;
|
||||
for (auto c : all)
|
||||
if (std::string::npos != m.find(c) && std::string::npos == found.find(c))
|
||||
found.append(1, c);
|
||||
m.assign(found);
|
||||
return m.empty();
|
||||
}
|
||||
|
||||
void CConfigure::setAutolink(const std::string §ion, const std::string &key, const std::string &value)
|
||||
{
|
||||
auto c = toupper(value.at(0));
|
||||
if (isupper(c))
|
||||
data[key] = std::string(1, c);
|
||||
else
|
||||
std::cout << "WARNING: line #" << counter << ": " << section << " AutoLinkModule is invalid: '" << value.substr(0, 1) << "'" << std::endl;
|
||||
}
|
||||
|
||||
void CConfigure::checkFile(const std::string §ion, const std::string &key, const std::string &filepath) const
|
||||
{
|
||||
struct stat sstat;
|
||||
auto rval = stat(filepath.c_str(), &sstat);
|
||||
if (rval)
|
||||
{
|
||||
std::cout << "WARNING: [" << section << ']' << key << " \"" << filepath << "\": " << strerror(errno) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void CConfigure::Dump(bool justpublic) const
|
||||
{
|
||||
nlohmann::json tmpjson = data;
|
||||
if (justpublic)
|
||||
{
|
||||
for (auto &it : data.items())
|
||||
{
|
||||
if (islower(it.key().at(0)))
|
||||
tmpjson.erase(it.key());
|
||||
}
|
||||
}
|
||||
std::cout << tmpjson.dump(4) << std::endl;
|
||||
}
|
||||
|
||||
ERefreshType CConfigure::GetRefreshType(const std::string &key) const
|
||||
{
|
||||
ERefreshType type = ERefreshType::http;
|
||||
if (data.contains(key))
|
||||
{
|
||||
if (data[key].is_string())
|
||||
{
|
||||
auto s = data[key].get<std::string>();
|
||||
if (0 == s.compare("both"))
|
||||
type = ERefreshType::both;
|
||||
else if (0 == s.compare("file"))
|
||||
type = ERefreshType::file;
|
||||
else
|
||||
type = ERefreshType::http;
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
bool CConfigure::Contains(const std::string &key) const
|
||||
{
|
||||
return data.contains(key);
|
||||
}
|
||||
|
||||
std::string CConfigure::GetString(const std::string &key) const
|
||||
{
|
||||
std::string str;
|
||||
if (data.contains(key))
|
||||
{
|
||||
if (data[key].is_null())
|
||||
{
|
||||
// null is the same thing as an empty string
|
||||
return str;
|
||||
}
|
||||
else if (data[key].is_string())
|
||||
{
|
||||
str.assign(data[key].get<std::string>());
|
||||
}
|
||||
else
|
||||
std::cerr << "ERROR: GetString(): '" << key << "' is not a string" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "ERROR: GetString(): item at '" << key << "' is not defined" << std::endl;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
unsigned CConfigure::GetUnsigned(const std::string &key) const
|
||||
{
|
||||
unsigned u = 0;
|
||||
if (data.contains(key))
|
||||
{
|
||||
if (data[key].is_number_unsigned())
|
||||
{
|
||||
u = data[key].get<unsigned>();
|
||||
}
|
||||
else
|
||||
std::cerr << "ERROR: GetUnsigned(): '" << key << "' is not an unsigned value" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "ERROR: GetUnsigned(): item at '" << key << "' is not defined" << std::endl;
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
bool CConfigure::GetBoolean(const std::string &key) const
|
||||
{
|
||||
if (data[key].is_boolean())
|
||||
return data[key];
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
char CConfigure::GetAutolinkModule(const std::string &key) const
|
||||
{
|
||||
char c = 0;
|
||||
if (data.contains(key))
|
||||
{
|
||||
if (data[key].is_string())
|
||||
{
|
||||
c = data[key].get<std::string>().at(0);
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
bool CConfigure::IsString(const std::string &key) const
|
||||
{
|
||||
if (data.contains(key))
|
||||
return data[key].is_string();
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef INICHECK
|
||||
SJsonKeys g_Keys;
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (3 == argc && strlen(argv[1]) > 1 && '-' == argv[1][0])
|
||||
{
|
||||
CConfigure d;
|
||||
auto rval = d.ReadData(argv[2]);
|
||||
if ('q' != argv[1][1])
|
||||
d.Dump(('n' == argv[1][1]) ? true : false);
|
||||
return rval ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
std::cerr << "Usage: " << argv[0] << " -(q|n|v) FILENAME\nWhere:\n\t-q just prints warnings and errors.\n\t-n also prints keys that begin with an uppercase letter.\n\t-v prints all keys, warnings and errors." << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2023 by Thomas A. Early N7TAE
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <regex>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
enum class ErrorLevel { fatal, mild };
|
||||
enum class ERefreshType { file, http, both };
|
||||
enum class ESection { none, names, ip, modules, urf, dplus, dextra, dcs, g3, dmrplus, mmdvm, nxdn, bm, ysf, p25, m17, usrp, dmrid, nxdnid, ysffreq, files };
|
||||
|
||||
#define IS_TRUE(a) ((a)=='t' || (a)=='T' || (a)=='1')
|
||||
|
||||
class CConfigure
|
||||
{
|
||||
public:
|
||||
CConfigure();
|
||||
bool ReadData(const std::string &path);
|
||||
bool Contains(const std::string &key) const;
|
||||
void Dump(bool justpublic) const;
|
||||
std::string GetString(const std::string &key) const;
|
||||
unsigned GetUnsigned(const std::string &key) const;
|
||||
bool GetBoolean(const std::string &key) const;
|
||||
ERefreshType GetRefreshType(const std::string &key) const;
|
||||
bool IsString(const std::string &key) const;
|
||||
char GetAutolinkModule(const std::string &key) const;
|
||||
const nlohmann::json &GetData() { return data; }
|
||||
|
||||
private:
|
||||
// CFGDATA data;
|
||||
unsigned counter;
|
||||
nlohmann::json data;
|
||||
std::regex IPv4RegEx, IPv6RegEx;
|
||||
|
||||
std::string getDataRefreshType(ERefreshType t) const;
|
||||
unsigned getUnsigned(const std::string &value, const std::string &label, unsigned min, unsigned max, unsigned defaultvalue) const;
|
||||
void badParam(const std::string ¶m) const;
|
||||
bool checkModules(std::string &m) const;
|
||||
void checkFile(const std::string §ion, const std::string &key, const std::string &filepath) const;
|
||||
void setAutolink(const std::string §ion, const std::string &key, const std::string &value);
|
||||
bool isDefined(ErrorLevel level, const std::string §ion, const std::string &pname, const std::string &key, bool &rval);
|
||||
void checkAutoLink(const std::string §ion, const std::string &pname, const std::string &key, bool &rval);
|
||||
};
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2023 by Thomas A. Early N7TAE
|
||||
*
|
||||
* 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 "CurlGet.h"
|
||||
|
||||
CCurlGet::CCurlGet()
|
||||
{
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
}
|
||||
|
||||
CCurlGet::~CCurlGet()
|
||||
{
|
||||
curl_global_cleanup();
|
||||
}
|
||||
|
||||
// callback function writes data to a std::ostream
|
||||
size_t CCurlGet::data_write(void* buf, size_t size, size_t nmemb, void* userp)
|
||||
{
|
||||
if(userp)
|
||||
{
|
||||
std::ostream& os = *static_cast<std::ostream*>(userp);
|
||||
std::streamsize len = size * nmemb;
|
||||
if(os.write(static_cast<char*>(buf), len))
|
||||
return len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CURLcode CCurlGet::GetURL(const std::string &url, std::stringstream &ss, long timeout)
|
||||
{
|
||||
CURLcode code(CURLE_FAILED_INIT);
|
||||
CURL* curl = curl_easy_init();
|
||||
|
||||
if(curl)
|
||||
{
|
||||
if(CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &data_write))
|
||||
&& CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L))
|
||||
&& CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L))
|
||||
&& CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_FILE, &ss))
|
||||
&& CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout))
|
||||
&& CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_URL, url.c_str())))
|
||||
{
|
||||
code = curl_easy_perform(curl);
|
||||
}
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
if (code != CURLE_OK)
|
||||
{
|
||||
std::cout << "ERROR: was not able retrieve data at '" << url << "'\nCurl returned: " << code << std::endl;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2023 by Thomas A. Early N7TAE
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
class CCurlGet
|
||||
{
|
||||
public:
|
||||
CCurlGet();
|
||||
~CCurlGet();
|
||||
// the contents of the URL will be appended to the stringstream.
|
||||
CURLcode GetURL(const std::string &url, std::stringstream &ss, long timeout = 30);
|
||||
private:
|
||||
static size_t data_write(void* buf, size_t size, size_t nmemb, void* userp);
|
||||
};
|
||||
@@ -16,7 +16,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
|
||||
#include "DCSClient.h"
|
||||
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Defines.h"
|
||||
#include "Client.h"
|
||||
|
||||
class CDcsClient : public CClient
|
||||
|
||||
@@ -16,12 +16,11 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
#include <string.h>
|
||||
|
||||
#include "Global.h"
|
||||
#include "DCSClient.h"
|
||||
#include "DCSProtocol.h"
|
||||
#include "Reflector.h"
|
||||
#include "GateKeeper.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// operation
|
||||
@@ -219,11 +218,10 @@ void CDcsProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
|
||||
|
||||
void CDcsProtocol::HandleQueue(void)
|
||||
{
|
||||
m_Queue.Lock();
|
||||
while ( !m_Queue.empty() )
|
||||
while (! m_Queue.IsEmpty())
|
||||
{
|
||||
// get the packet
|
||||
auto packet = m_Queue.pop();
|
||||
auto packet = m_Queue.Pop();
|
||||
|
||||
// get our sender's id
|
||||
const auto module = packet->GetPacketModule();
|
||||
@@ -270,7 +268,6 @@ void CDcsProtocol::HandleQueue(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
m_Queue.Unlock();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Defines.h"
|
||||
#include "Timer.h"
|
||||
#include "Protocol.h"
|
||||
#include "DVHeaderPacket.h"
|
||||
|
||||
@@ -16,10 +16,8 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
#include "DExtraClient.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructors
|
||||
|
||||
|
||||
@@ -18,15 +18,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Defines.h"
|
||||
#include "Client.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// define
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CDextraClient : public CClient
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
// Created by Antony Chazapis (SV9OAN) on 25/2/2018.
|
||||
// Copyright © 2016 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
|
||||
// urfd -- The universal reflector
|
||||
// Copyright © 2021 Thomas A. Early N7TAE
|
||||
//
|
||||
// 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 3 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, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
#include <string.h>
|
||||
#include "Reflector.h"
|
||||
#include "DExtraPeer.h"
|
||||
#include "DExtraClient.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor
|
||||
|
||||
|
||||
CDextraPeer::CDextraPeer()
|
||||
{
|
||||
}
|
||||
|
||||
CDextraPeer::CDextraPeer(const CCallsign &callsign, const CIp &ip, const char *modules, const CVersion &version)
|
||||
: CPeer(callsign, ip, modules, version)
|
||||
{
|
||||
std::cout << "Adding DExtra peer" << std::endl;
|
||||
|
||||
// and construct the DExtra clients
|
||||
for ( unsigned i = 0; i < ::strlen(modules); i++ )
|
||||
{
|
||||
// create and append to list
|
||||
m_Clients.push_back(std::make_shared<CDextraClient>(callsign, ip, modules[i], EProtoRev::ambe));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// status
|
||||
|
||||
bool CDextraPeer::IsAlive(void) const
|
||||
{
|
||||
for ( auto it=cbegin(); it!=cend(); it++ )
|
||||
{
|
||||
if (! (*it)->IsAlive())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// revision helper
|
||||
|
||||
int CDextraPeer::GetProtocolRevision(const CVersion &version)
|
||||
{
|
||||
return version.GetMajor();
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
// Created by Antony Chazapis (SV9OAN) on 25/2/2018.
|
||||
// Copyright © 2016 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
|
||||
// urfd -- The universal reflector
|
||||
// Copyright © 2021 Thomas A. Early N7TAE
|
||||
//
|
||||
// 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 3 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, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Peer.h"
|
||||
#include "DExtraClient.h"
|
||||
|
||||
class CDextraPeer : public CPeer
|
||||
{
|
||||
public:
|
||||
// constructors
|
||||
CDextraPeer();
|
||||
CDextraPeer(const CCallsign &, const CIp &, const char *, const CVersion &);
|
||||
CDextraPeer(const CDextraPeer &) = delete;
|
||||
|
||||
// status
|
||||
bool IsAlive(void) const;
|
||||
|
||||
// identity
|
||||
EProtocol GetProtocol(void) const { return EProtocol::dextra; }
|
||||
const char *GetProtocolName(void) const { return "DExtra"; }
|
||||
|
||||
// revision helper
|
||||
static int GetProtocolRevision(const CVersion &);
|
||||
};
|
||||
+12
-101
@@ -16,14 +16,13 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "DExtraPeer.h"
|
||||
|
||||
#include "Global.h"
|
||||
#include "DExtraClient.h"
|
||||
#include "DExtraProtocol.h"
|
||||
#include "Reflector.h"
|
||||
#include "GateKeeper.h"
|
||||
|
||||
#
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// operation
|
||||
@@ -36,7 +35,6 @@ bool CDextraProtocol::Initialize(const char *type, const EProtocol ptype, const
|
||||
|
||||
// update time
|
||||
m_LastKeepaliveTime.start();
|
||||
m_LastPeersLinkTime.start();
|
||||
|
||||
// done
|
||||
return true;
|
||||
@@ -103,36 +101,13 @@ void CDextraProtocol::Task(void)
|
||||
// valid module ?
|
||||
if ( g_Reflector.IsValidModule(ToLinkModule) )
|
||||
{
|
||||
// is this an ack for a link request?
|
||||
CPeerCallsignList *list = g_GateKeeper.GetPeerList();
|
||||
CCallsignListItem *item = list->FindListItem(Callsign);
|
||||
if ( item != nullptr && Callsign.GetCSModule() == item->GetModules()[1] && ToLinkModule == item->GetModules()[0] )
|
||||
{
|
||||
std::cout << "DExtra ack packet for module " << ToLinkModule << " from " << Callsign << " at " << Ip << std::endl;
|
||||
// acknowledge the request
|
||||
EncodeConnectAckPacket(&Buffer, ProtRev);
|
||||
Send(Buffer, Ip);
|
||||
|
||||
// already connected ?
|
||||
CPeers *peers = g_Reflector.GetPeers();
|
||||
if ( peers->FindPeer(Callsign, Ip, EProtocol::dextra) == nullptr )
|
||||
{
|
||||
// create the new peer
|
||||
// this also create one client per module
|
||||
// append the peer to reflector peer list
|
||||
// this also add all new clients to reflector client list
|
||||
peers->AddPeer(std::make_shared<CDextraPeer>(Callsign, Ip, std::string(1, ToLinkModule).c_str(), CVersion(2, 0, 0)));
|
||||
}
|
||||
g_Reflector.ReleasePeers();
|
||||
}
|
||||
else
|
||||
{
|
||||
// acknowledge the request
|
||||
EncodeConnectAckPacket(&Buffer, ProtRev);
|
||||
Send(Buffer, Ip);
|
||||
|
||||
// create the client and append
|
||||
g_Reflector.GetClients()->AddClient(std::make_shared<CDextraClient>(Callsign, Ip, ToLinkModule, ProtRev));
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
g_GateKeeper.ReleasePeerList();
|
||||
// create the client and append
|
||||
g_Reflector.GetClients()->AddClient(std::make_shared<CDextraClient>(Callsign, Ip, ToLinkModule, ProtRev));
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -211,16 +186,6 @@ void CDextraProtocol::Task(void)
|
||||
// update time
|
||||
m_LastKeepaliveTime.start();
|
||||
}
|
||||
|
||||
// peer connections
|
||||
if ( m_LastPeersLinkTime.time() > DEXTRA_RECONNECT_PERIOD )
|
||||
{
|
||||
// handle remote peers connections
|
||||
HandlePeerLinks();
|
||||
|
||||
// update time
|
||||
m_LastPeersLinkTime.start();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -228,11 +193,10 @@ void CDextraProtocol::Task(void)
|
||||
|
||||
void CDextraProtocol::HandleQueue(void)
|
||||
{
|
||||
m_Queue.Lock();
|
||||
while ( !m_Queue.empty() )
|
||||
while (! m_Queue.IsEmpty() )
|
||||
{
|
||||
// get the packet
|
||||
auto packet = m_Queue.pop();
|
||||
auto packet = m_Queue.Pop();
|
||||
|
||||
// encode it
|
||||
CBuffer buffer;
|
||||
@@ -258,7 +222,6 @@ void CDextraProtocol::HandleQueue(void)
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
}
|
||||
m_Queue.Unlock();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -342,58 +305,6 @@ void CDextraProtocol::HandleKeepalives(void)
|
||||
g_Reflector.ReleasePeers();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Peers helpers
|
||||
|
||||
void CDextraProtocol::HandlePeerLinks(void)
|
||||
{
|
||||
CBuffer buffer;
|
||||
|
||||
// get the list of peers
|
||||
CPeerCallsignList *list = g_GateKeeper.GetPeerList();
|
||||
CPeers *peers = g_Reflector.GetPeers();
|
||||
|
||||
// check if all our connected peers are still listed by gatekeeper
|
||||
// if not, disconnect
|
||||
auto pit = peers->begin();
|
||||
std::shared_ptr<CPeer>peer = nullptr;
|
||||
while ( (peer = peers->FindNextPeer(EProtocol::dextra, pit)) != nullptr )
|
||||
{
|
||||
if ( list->FindListItem(peer->GetCallsign()) == nullptr )
|
||||
{
|
||||
// send disconnect packet
|
||||
EncodeDisconnectPacket(&buffer, peer->GetReflectorModules()[0]);
|
||||
Send(buffer, peer->GetIp());
|
||||
std::cout << "Sending disconnect packet to XRF peer " << peer->GetCallsign() << " at " << peer->GetIp() << std::endl;
|
||||
// remove client
|
||||
peers->RemovePeer(peer);
|
||||
}
|
||||
}
|
||||
|
||||
// check if all ours peers listed by gatekeeper are connected
|
||||
// if not, connect or reconnect
|
||||
for ( auto it=list->begin(); it!=list->end(); it++ )
|
||||
{
|
||||
if ( !it->GetCallsign().HasSameCallsignWithWildcard(CCallsign("XRF*")) )
|
||||
continue;
|
||||
if ( strlen(it->GetModules()) != 2 )
|
||||
continue;
|
||||
if ( peers->FindPeer(it->GetCallsign(), EProtocol::dextra) == nullptr )
|
||||
{
|
||||
// resolve again peer's IP in case it's a dynamic IP
|
||||
it->ResolveIp();
|
||||
// send connect packet to re-initiate peer link
|
||||
EncodeConnectPacket(&buffer, it->GetModules());
|
||||
Send(buffer, it->GetIp(), DEXTRA_PORT);
|
||||
std::cout << "Sending connect packet to XRF peer " << it->GetCallsign() << " @ " << it->GetIp() << " for module " << it->GetModules()[1] << " (module " << it->GetModules()[0] << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// done
|
||||
g_Reflector.ReleasePeers();
|
||||
g_GateKeeper.ReleasePeerList();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// streams helpers
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Defines.h"
|
||||
#include "Timer.h"
|
||||
#include "SEProtocol.h"
|
||||
#include "DVHeaderPacket.h"
|
||||
@@ -61,7 +62,6 @@ protected:
|
||||
void HandleQueue(void);
|
||||
|
||||
// keepalive helpers
|
||||
void HandlePeerLinks(void);
|
||||
void HandleKeepalives(void);
|
||||
|
||||
// stream helpers
|
||||
@@ -84,8 +84,6 @@ protected:
|
||||
bool EncodeDvHeaderPacket(const CDvHeaderPacket &, CBuffer &) const;
|
||||
bool EncodeDvFramePacket(const CDvFramePacket &, CBuffer &) const;
|
||||
|
||||
protected:
|
||||
// time
|
||||
CTimer m_LastKeepaliveTime;
|
||||
CTimer m_LastPeersLinkTime;
|
||||
};
|
||||
@@ -1,145 +0,0 @@
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
|
||||
// urfd -- The universal reflector
|
||||
// Copyright © 2021 Thomas A. Early N7TAE
|
||||
//
|
||||
// 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 3 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, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <string.h>
|
||||
#include "Main.h"
|
||||
#include "Reflector.h"
|
||||
#include "DMRIdDir.h"
|
||||
#include "DMRIdDirFile.h"
|
||||
#include "DMRIdDirHttp.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor & destructor
|
||||
|
||||
CDmridDir::CDmridDir()
|
||||
{
|
||||
keep_running = true;
|
||||
}
|
||||
|
||||
CDmridDir::~CDmridDir()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// init & close
|
||||
|
||||
bool CDmridDir::Init(void)
|
||||
{
|
||||
// load content
|
||||
Reload();
|
||||
|
||||
// reset run flag
|
||||
keep_running = true;
|
||||
|
||||
// start thread;
|
||||
m_Future = std::async(std::launch::async, &CDmridDir::Thread, this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDmridDir::Close(void)
|
||||
{
|
||||
keep_running = false;
|
||||
if ( m_Future.valid() )
|
||||
{
|
||||
m_Future.get();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// thread
|
||||
|
||||
void CDmridDir::Thread()
|
||||
{
|
||||
while (keep_running)
|
||||
{
|
||||
// Wait DMRIDDB_REFRESH_RATE minutes
|
||||
for (int i=0; i<30*DMRIDDB_REFRESH_RATE && keep_running; i++)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
|
||||
|
||||
// have lists files changed ?
|
||||
if ( NeedReload() )
|
||||
{
|
||||
Reload();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Reload
|
||||
|
||||
bool CDmridDir::Reload(void)
|
||||
{
|
||||
CBuffer buffer;
|
||||
bool ok = false;
|
||||
|
||||
if ( LoadContent(&buffer) )
|
||||
{
|
||||
Lock();
|
||||
{
|
||||
ok = RefreshContent(buffer);
|
||||
}
|
||||
Unlock();
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// find
|
||||
|
||||
const CCallsign *CDmridDir::FindCallsign(uint32_t dmrid)
|
||||
{
|
||||
auto found = m_CallsignMap.find(dmrid);
|
||||
if ( found != m_CallsignMap.end() )
|
||||
{
|
||||
return &(found->second);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t CDmridDir::FindDmrid(const CCallsign &callsign)
|
||||
{
|
||||
auto found = m_DmridMap.find(callsign);
|
||||
if ( found != m_DmridMap.end() )
|
||||
{
|
||||
return (found->second);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// syntax helpers
|
||||
|
||||
bool CDmridDir::IsValidDmrid(const char *sz)
|
||||
{
|
||||
bool ok = false;
|
||||
size_t n = ::strlen(sz);
|
||||
if ( (n > 0) && (n <= 8) )
|
||||
{
|
||||
ok = true;
|
||||
for ( size_t i = 0; (i < n) && ok; i++ )
|
||||
{
|
||||
ok &= ::isdigit(sz[i]);
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
|
||||
// urfd -- The universal reflector
|
||||
// Copyright © 2021 Thomas A. Early N7TAE
|
||||
//
|
||||
// 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 3 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, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include "Main.h"
|
||||
#include "DMRIdDirFile.h"
|
||||
|
||||
|
||||
#if (DMRIDDB_USE_RLX_SERVER == 0)
|
||||
CDmridDirFile g_DmridDir;
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor & destructor
|
||||
|
||||
CDmridDirFile::CDmridDirFile()
|
||||
{
|
||||
memset(&m_LastModTime, 0, sizeof(time_t));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// init & close
|
||||
|
||||
bool CDmridDirFile::Init(void)
|
||||
{
|
||||
return CDmridDir::Init();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// refresh
|
||||
|
||||
bool CDmridDirFile::NeedReload(void)
|
||||
{
|
||||
bool needReload = false;
|
||||
|
||||
time_t time;
|
||||
if ( GetLastModTime(&time) )
|
||||
{
|
||||
needReload = time != m_LastModTime;
|
||||
}
|
||||
return needReload;
|
||||
}
|
||||
|
||||
bool CDmridDirFile::LoadContent(CBuffer *buffer)
|
||||
{
|
||||
bool ok = false;
|
||||
std::ifstream file;
|
||||
std::streampos size;
|
||||
|
||||
// open file
|
||||
file.open(DMRIDDB_PATH, std::ios::in | std::ios::binary | std::ios::ate);
|
||||
if ( file.is_open() )
|
||||
{
|
||||
// read file
|
||||
size = file.tellg();
|
||||
if ( size > 0 )
|
||||
{
|
||||
// read file into buffer
|
||||
buffer->resize((int)size+1);
|
||||
file.seekg (0, std::ios::beg);
|
||||
file.read((char *)buffer->data(), (int)size);
|
||||
|
||||
// close file
|
||||
file.close();
|
||||
|
||||
// update time
|
||||
GetLastModTime(&m_LastModTime);
|
||||
|
||||
// done
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
// done
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool CDmridDirFile::RefreshContent(const CBuffer &buffer)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
// clear directory
|
||||
m_CallsignMap.clear();
|
||||
m_DmridMap.clear();
|
||||
|
||||
// scan buffer
|
||||
if ( buffer.size() > 0 )
|
||||
{
|
||||
// crack it
|
||||
char *ptr1 = (char *)buffer.data();
|
||||
char *ptr2;
|
||||
|
||||
// get next line
|
||||
while ( (ptr2 = ::strchr(ptr1, '\n')) != nullptr )
|
||||
{
|
||||
*ptr2 = 0;
|
||||
// get items
|
||||
char *dmrid;
|
||||
char *callsign;
|
||||
if ( ((dmrid = ::strtok(ptr1, ";")) != nullptr) && IsValidDmrid(dmrid) )
|
||||
{
|
||||
if ( ((callsign = ::strtok(nullptr, ";")) != nullptr) )
|
||||
{
|
||||
// new entry
|
||||
uint32_t ui = atoi(dmrid);
|
||||
CCallsign cs(callsign, ui);
|
||||
if ( cs.IsValid() )
|
||||
{
|
||||
m_CallsignMap.insert(std::pair<uint32_t,CCallsign>(ui, cs));
|
||||
m_DmridMap.insert(std::pair<CCallsign,uint32_t>(cs,ui));
|
||||
}
|
||||
}
|
||||
}
|
||||
// next line
|
||||
ptr1 = ptr2+1;
|
||||
}
|
||||
|
||||
// done
|
||||
ok = true;
|
||||
}
|
||||
|
||||
// report
|
||||
std::cout << "Read " << m_DmridMap.size() << " DMR ids from file " << DMRIDDB_PATH << std::endl;
|
||||
|
||||
// done
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
bool CDmridDirFile::GetLastModTime(time_t *time)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
struct stat fileStat;
|
||||
if( ::stat(DMRIDDB_PATH, &fileStat) != -1 )
|
||||
{
|
||||
*time = fileStat.st_mtime;
|
||||
ok = true;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
|
||||
// urfd -- The universal reflector
|
||||
// Copyright © 2021 Thomas A. Early N7TAE
|
||||
//
|
||||
// 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 3 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, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "DMRIdDir.h"
|
||||
|
||||
class CDmridDirFile : public CDmridDir
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CDmridDirFile();
|
||||
|
||||
// destructor
|
||||
~CDmridDirFile() {}
|
||||
|
||||
// init & close
|
||||
bool Init(void);
|
||||
|
||||
// refresh
|
||||
bool LoadContent(CBuffer *);
|
||||
bool RefreshContent(const CBuffer &);
|
||||
|
||||
protected:
|
||||
// reload helpers
|
||||
bool NeedReload(void);
|
||||
bool GetLastModTime(time_t *);
|
||||
|
||||
protected:
|
||||
// data
|
||||
time_t m_LastModTime;
|
||||
};
|
||||
@@ -1,177 +0,0 @@
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
|
||||
// urfd -- The universal reflector
|
||||
// Copyright © 2021 Thomas A. Early N7TAE
|
||||
// Copyright © 2021 Doug McLain AD8DP
|
||||
//
|
||||
// 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 3 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, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <string.h>
|
||||
#include "Main.h"
|
||||
#include "Reflector.h"
|
||||
#include "DMRIdDirHttp.h"
|
||||
|
||||
#if (DMRIDDB_USE_RLX_SERVER == 1)
|
||||
CDmridDirHttp g_DmridDir;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// refresh
|
||||
|
||||
bool CDmridDirHttp::LoadContent(CBuffer *buffer)
|
||||
{
|
||||
// get file from xlxapi server
|
||||
return HttpGet("xlxapi.rlx.lu", "api/exportdmr.php", 80, buffer);
|
||||
}
|
||||
|
||||
bool CDmridDirHttp::RefreshContent(const CBuffer &buffer)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
// clear directory
|
||||
m_CallsignMap.clear();
|
||||
m_DmridMap.clear();
|
||||
|
||||
// scan file
|
||||
if ( buffer.size() > 0 )
|
||||
{
|
||||
char *ptr1 = (char *)buffer.data();
|
||||
char *ptr2;
|
||||
// get next line
|
||||
while ( (ptr2 = ::strchr(ptr1, '\n')) != nullptr )
|
||||
{
|
||||
*ptr2 = 0;
|
||||
// get items
|
||||
char *dmrid;
|
||||
char *callsign;
|
||||
if ( ((dmrid = ::strtok(ptr1, ";")) != nullptr) && IsValidDmrid(dmrid) )
|
||||
{
|
||||
if ( ((callsign = ::strtok(nullptr, ";")) != nullptr) )
|
||||
{
|
||||
// new entry
|
||||
uint32_t ui = atoi(dmrid);
|
||||
CCallsign cs(callsign, ui);
|
||||
if ( cs.IsValid() )
|
||||
{
|
||||
m_CallsignMap.insert(std::pair<uint32_t,CCallsign>(ui, cs));
|
||||
m_DmridMap.insert(std::pair<CCallsign,uint32_t>(cs,ui));
|
||||
}
|
||||
}
|
||||
}
|
||||
// next line
|
||||
ptr1 = ptr2+1;
|
||||
}
|
||||
// done
|
||||
ok = true;
|
||||
}
|
||||
|
||||
// report
|
||||
std::cout << "Read " << m_DmridMap.size() << " DMR ids from xlxapi.rlx.lu database " << std::endl;
|
||||
|
||||
// done
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// httpd helpers
|
||||
|
||||
#define DMRID_HTTPGET_SIZEMAX (256)
|
||||
|
||||
bool CDmridDirHttp::HttpGet(const char *hostname, const char *filename, int port, CBuffer *buffer)
|
||||
{
|
||||
bool ok = false;
|
||||
int sock_id;
|
||||
|
||||
// open socket
|
||||
if ( (sock_id = ::socket(AF_INET, SOCK_STREAM, 0)) >= 0 )
|
||||
{
|
||||
// get hostname address
|
||||
struct sockaddr_in servaddr;
|
||||
struct hostent *hp;
|
||||
memset(&servaddr,0,sizeof(servaddr));
|
||||
if( (hp = gethostbyname(hostname)) != nullptr )
|
||||
{
|
||||
// dns resolved
|
||||
memcpy((char *)&servaddr.sin_addr.s_addr, (char *)hp->h_addr, hp->h_length);
|
||||
servaddr.sin_port = htons(port);
|
||||
servaddr.sin_family = AF_INET;
|
||||
|
||||
// connect
|
||||
if ( ::connect(sock_id, (struct sockaddr *)&servaddr, sizeof(servaddr)) == 0)
|
||||
{
|
||||
// send the GET request
|
||||
char request[DMRID_HTTPGET_SIZEMAX];
|
||||
::sprintf(request, "GET /%s HTTP/1.0\r\nFrom: %s\r\nUser-Agent: urfd\r\n\r\n",
|
||||
filename, (const char *)g_Reflector.GetCallsign());
|
||||
::write(sock_id, request, strlen(request));
|
||||
|
||||
// config receive timeouts
|
||||
fd_set read_set;
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 5;
|
||||
timeout.tv_usec = 0;
|
||||
FD_ZERO(&read_set);
|
||||
FD_SET(sock_id, &read_set);
|
||||
|
||||
// get the reply back
|
||||
buffer->clear();
|
||||
bool done = false;
|
||||
do
|
||||
{
|
||||
char buf[1440];
|
||||
ssize_t len = 0;
|
||||
select(sock_id+1, &read_set, nullptr, nullptr, &timeout);
|
||||
//if ( (ret > 0) || ((ret < 0) && (errno == EINPROGRESS)) )
|
||||
//if ( ret >= 0 )
|
||||
//{
|
||||
usleep(5000);
|
||||
len = read(sock_id, buf, 1440);
|
||||
if ( len > 0 )
|
||||
{
|
||||
buffer->Append((uint8_t *)buf, (int)len);
|
||||
ok = true;
|
||||
}
|
||||
//}
|
||||
done = (len <= 0);
|
||||
|
||||
}
|
||||
while (!done);
|
||||
buffer->Append((uint8_t)0);
|
||||
|
||||
// and disconnect
|
||||
close(sock_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Cannot establish connection with host " << hostname << std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Host " << hostname << " not found" << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Failed to open wget socket" << std::endl;
|
||||
}
|
||||
|
||||
// done
|
||||
return ok;
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
|
||||
#include "DMRMMDVMClient.h"
|
||||
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Defines.h"
|
||||
#include "Client.h"
|
||||
|
||||
class CDmrmmdvmClient : public CClient
|
||||
|
||||
@@ -16,18 +16,17 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "Global.h"
|
||||
#include "DMRMMDVMClient.h"
|
||||
#include "DMRMMDVMProtocol.h"
|
||||
#include "Reflector.h"
|
||||
#include "GateKeeper.h"
|
||||
#include "BPTC19696.h"
|
||||
#include "RS129.h"
|
||||
#include "Golay2087.h"
|
||||
#include "QR1676.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// define
|
||||
|
||||
@@ -49,6 +48,7 @@ static uint8_t g_DmrSyncMSData[] = { 0x0D,0x5D,0x7F,0x77,0xFD,0x75,0x70 };
|
||||
|
||||
bool CDmrmmdvmProtocol::Initialize(const char *type, const EProtocol ptype, const uint16_t port, const bool has_ipv4, const bool has_ipv6)
|
||||
{
|
||||
m_DefaultId = g_Configure.GetUnsigned(g_Keys.mmdvm.defaultid);
|
||||
// base class
|
||||
if (! CProtocol::Initialize(type, ptype, port, has_ipv4, has_ipv6))
|
||||
return false;
|
||||
@@ -346,12 +346,10 @@ void CDmrmmdvmProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Hea
|
||||
|
||||
void CDmrmmdvmProtocol::HandleQueue(void)
|
||||
{
|
||||
|
||||
m_Queue.Lock();
|
||||
while ( !m_Queue.empty() )
|
||||
while (! m_Queue.IsEmpty())
|
||||
{
|
||||
// get the packet
|
||||
auto packet = m_Queue.pop();
|
||||
auto packet = m_Queue.Pop();
|
||||
|
||||
// get our sender's id
|
||||
const auto mod = packet->GetPacketModule();
|
||||
@@ -419,7 +417,6 @@ void CDmrmmdvmProtocol::HandleQueue(void)
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
}
|
||||
m_Queue.Unlock();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -860,14 +857,14 @@ void CDmrmmdvmProtocol::EncodeMMDVMPacket(const CDvHeaderPacket &Header, const C
|
||||
uint8_t tag[] = { 'D','M','R','D' };
|
||||
Buffer->Set(tag, sizeof(tag));
|
||||
uint8_t cs[12];
|
||||
|
||||
|
||||
// DMR header
|
||||
// uiSeqId
|
||||
Buffer->Append((uint8_t)seqid);
|
||||
// uiSrcId
|
||||
uint32_t uiSrcId = Header.GetMyCallsign().GetDmrid();
|
||||
DvFrame0.GetMyCallsign().GetCallsign(cs);
|
||||
|
||||
|
||||
if(uiSrcId == 0){
|
||||
uiSrcId = DvFrame0.GetMyCallsign().GetDmrid();
|
||||
}
|
||||
@@ -878,9 +875,9 @@ void CDmrmmdvmProtocol::EncodeMMDVMPacket(const CDvHeaderPacket &Header, const C
|
||||
uiSrcId = DvFrame2.GetMyCallsign().GetDmrid();
|
||||
}
|
||||
if(uiSrcId == 0){
|
||||
uiSrcId = DMRMMDVM_DEFAULTID;
|
||||
uiSrcId = m_DefaultId;
|
||||
}
|
||||
|
||||
|
||||
AppendDmrIdToBuffer(Buffer, uiSrcId);
|
||||
// uiDstId = TG9
|
||||
uint32_t uiDstId = 9; // ModuleToDmrDestId(Header.GetRpt2Module());
|
||||
@@ -982,7 +979,7 @@ char CDmrmmdvmProtocol::DmrDstIdToModule(uint32_t tg) const
|
||||
if (tg > 4000 && tg < 4027)
|
||||
{
|
||||
const char mod = 'A' + (tg - 4001U);
|
||||
if (strchr(ACTIVE_MODULES, mod))
|
||||
if (g_Reflector.IsValidModule(mod))
|
||||
{
|
||||
return mod;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Defines.h"
|
||||
#include "Timer.h"
|
||||
#include "Protocol.h"
|
||||
#include "DVHeaderPacket.h"
|
||||
@@ -117,4 +118,7 @@ protected:
|
||||
|
||||
// for authentication
|
||||
uint32_t m_uiAuthSeed;
|
||||
|
||||
// config data
|
||||
unsigned m_DefaultId;
|
||||
};
|
||||
@@ -16,7 +16,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
|
||||
#include "DMRPlusClient.h"
|
||||
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Defines.h"
|
||||
#include "Client.h"
|
||||
|
||||
class CDmrplusClient : public CClient
|
||||
|
||||
@@ -16,13 +16,12 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "Global.h"
|
||||
#include "DMRPlusClient.h"
|
||||
#include "DMRPlusProtocol.h"
|
||||
#include "Reflector.h"
|
||||
#include "GateKeeper.h"
|
||||
#include "DMRIdDir.h"
|
||||
#include "BPTC19696.h"
|
||||
#include "RS129.h"
|
||||
#include "Golay2087.h"
|
||||
@@ -219,12 +218,10 @@ void CDmrplusProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Head
|
||||
|
||||
void CDmrplusProtocol::HandleQueue(void)
|
||||
{
|
||||
|
||||
m_Queue.Lock();
|
||||
while ( !m_Queue.empty() )
|
||||
while (! m_Queue.IsEmpty())
|
||||
{
|
||||
// get the packet
|
||||
auto packet = m_Queue.pop();
|
||||
auto packet = m_Queue.Pop();
|
||||
|
||||
// get our sender's id
|
||||
const auto mod = packet->GetPacketModule();
|
||||
@@ -286,7 +283,6 @@ void CDmrplusProtocol::HandleQueue(void)
|
||||
//buffer.DebugDump(g_Reflector.m_DebugFile);
|
||||
}
|
||||
}
|
||||
m_Queue.Unlock();
|
||||
}
|
||||
|
||||
void CDmrplusProtocol::SendBufferToClients(const CBuffer &buffer, uint8_t module)
|
||||
@@ -642,7 +638,7 @@ char CDmrplusProtocol::DmrDstIdToModule(uint32_t tg) const
|
||||
// is it a 4xxx ?
|
||||
if (tg > 4000 && tg < 4027) {
|
||||
char mod = 'A' + (tg - 4001U);
|
||||
if (strchr(ACTIVE_MODULES, mod))
|
||||
if (g_Reflector.IsValidModule(mod))
|
||||
{
|
||||
return mod;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Defines.h"
|
||||
#include "Timer.h"
|
||||
#include "Protocol.h"
|
||||
#include "DVHeaderPacket.h"
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
|
||||
#include "DPlusClient.h"
|
||||
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Defines.h"
|
||||
#include "Client.h"
|
||||
|
||||
class CDplusClient : public CClient
|
||||
|
||||
@@ -16,13 +16,12 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "Global.h"
|
||||
#include "DPlusClient.h"
|
||||
#include "DPlusProtocol.h"
|
||||
#include "Reflector.h"
|
||||
#include "GateKeeper.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// operation
|
||||
@@ -229,11 +228,10 @@ void CDplusProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header
|
||||
|
||||
void CDplusProtocol::HandleQueue(void)
|
||||
{
|
||||
m_Queue.Lock();
|
||||
while ( !m_Queue.empty() )
|
||||
while (! m_Queue.IsEmpty())
|
||||
{
|
||||
// get the packet
|
||||
auto packet = m_Queue.pop();
|
||||
auto packet = m_Queue.Pop();
|
||||
|
||||
// get our sender's id
|
||||
const auto mod = packet->GetPacketModule();
|
||||
@@ -293,7 +291,6 @@ void CDplusProtocol::HandleQueue(void)
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
}
|
||||
m_Queue.Unlock();
|
||||
}
|
||||
|
||||
void CDplusProtocol::SendDvHeader(CDvHeaderPacket *packet, CDplusClient *client)
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Defines.h"
|
||||
#include "Timer.h"
|
||||
#include "SEProtocol.h"
|
||||
#include "DVHeaderPacket.h"
|
||||
|
||||
+12
-23
@@ -16,7 +16,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
#include <iostream>
|
||||
#include <string.h>
|
||||
#include "DVFramePacket.h"
|
||||
|
||||
@@ -167,10 +167,15 @@ CDvFramePacket::CDvFramePacket(const int16_t *usrp, uint16_t streamid, bool isla
|
||||
m_TCPack.codec_in = ECodecType::usrp;
|
||||
}
|
||||
|
||||
std::unique_ptr<CPacket> CDvFramePacket::Copy(void)
|
||||
{
|
||||
return std::unique_ptr<CPacket>(new CDvFramePacket(*this));
|
||||
}
|
||||
|
||||
// Network
|
||||
unsigned int CDvFramePacket::GetNetworkSize()
|
||||
{
|
||||
return CPacket::GetNetworkSize() + 4 + 3 + 7 + 14 + 9 + 9 + 16;
|
||||
return CPacket::GetNetworkSize() + 4 + 3 + 7 + 14 + 9 + 9 + 16 + 11 + 320;
|
||||
}
|
||||
|
||||
CDvFramePacket::CDvFramePacket(const CBuffer &buf) : CPacket(buf)
|
||||
@@ -189,6 +194,8 @@ CDvFramePacket::CDvFramePacket(const CBuffer &buf) : CPacket(buf)
|
||||
memcpy(m_TCPack.dstar, data+off, 9); off += 9;
|
||||
memcpy(m_TCPack.dmr, data+off, 9); off += 9;
|
||||
memcpy(m_TCPack.m17, data+off, 16); off += 16;
|
||||
memcpy(m_TCPack.p25, data+off, 11); off += 11;
|
||||
memcpy(m_TCPack.usrp, data+off, 320);
|
||||
SetTCParams(seq);
|
||||
}
|
||||
else
|
||||
@@ -210,15 +217,9 @@ void CDvFramePacket::EncodeInterlinkPacket(CBuffer &buf) const
|
||||
memcpy(data+off, m_Nonce, 14); off += 14;
|
||||
memcpy(data+off, m_TCPack.dstar, 9); off += 9;
|
||||
memcpy(data+off, m_TCPack.dmr, 9); off += 9;
|
||||
memcpy(data+off, m_TCPack.m17, 16);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// virtual duplication
|
||||
|
||||
std::unique_ptr<CPacket> CDvFramePacket::Duplicate(void) const
|
||||
{
|
||||
return std::unique_ptr<CPacket>(new CDvFramePacket(*this));
|
||||
memcpy(data+off, m_TCPack.m17, 16); off += 16;
|
||||
memcpy(data+off, m_TCPack.p25, 11); off += 11;
|
||||
memcpy(data+off, m_TCPack.usrp, 320);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -265,15 +266,3 @@ void CDvFramePacket::SetTCParams(uint32_t seq)
|
||||
m_TCPack.module = m_cModule;
|
||||
m_TCPack.rt_timer.start();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// operators
|
||||
|
||||
bool CDvFramePacket::operator ==(const CDvFramePacket &DvFrame) const
|
||||
{
|
||||
return ( (memcmp(m_TCPack.dstar, DvFrame.m_TCPack.dstar, 9) == 0)
|
||||
&& (memcmp(m_uiDvData, DvFrame.m_uiDvData, 3) == 0)
|
||||
&& (memcmp(m_TCPack.dmr, DvFrame.m_TCPack.dmr, 9) == 0)
|
||||
&& (memcmp(m_uiDvSync, DvFrame.m_uiDvSync, 7) == 0)
|
||||
);
|
||||
}
|
||||
@@ -62,10 +62,8 @@ public:
|
||||
static unsigned int GetNetworkSize();
|
||||
void EncodeInterlinkPacket(CBuffer &buf) const;
|
||||
|
||||
// virtual duplication
|
||||
std::unique_ptr<CPacket> Duplicate(void) const;
|
||||
|
||||
// identity
|
||||
std::unique_ptr<CPacket> Copy(void);
|
||||
bool IsDvHeader(void) const { return false; }
|
||||
bool IsDvFrame(void) const { return true; }
|
||||
|
||||
@@ -82,9 +80,6 @@ public:
|
||||
void SetCodecData(const STCPacket *pack);
|
||||
void SetTCParams(uint32_t seq);
|
||||
|
||||
// operators
|
||||
bool operator ==(const CDvFramePacket &) const;
|
||||
|
||||
protected:
|
||||
// data (dstar)
|
||||
uint8_t m_uiDvData[3];
|
||||
|
||||
@@ -16,12 +16,12 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
#include <string.h>
|
||||
#include <cstdio>
|
||||
#include "DMRIdDir.h"
|
||||
#include "DVHeaderPacket.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <iostream>
|
||||
|
||||
#include "Defines.h"
|
||||
#include "DVHeaderPacket.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor
|
||||
@@ -90,7 +90,7 @@ CDvHeaderPacket::CDvHeaderPacket(const struct dstar_header *buffer, uint16_t sid
|
||||
m_uiFlag2 = buffer->Flag2;
|
||||
m_uiFlag3 = buffer->Flag3;
|
||||
m_csUR.SetCallsign(buffer->UR, CALLSIGN_LEN);
|
||||
|
||||
|
||||
if((buffer->RPT1)[7] == 0x20){
|
||||
char rptr1[8];
|
||||
memcpy(rptr1, buffer->RPT1, 8);
|
||||
@@ -100,7 +100,7 @@ CDvHeaderPacket::CDvHeaderPacket(const struct dstar_header *buffer, uint16_t sid
|
||||
else{
|
||||
m_csRPT1.SetCallsign(buffer->RPT1, CALLSIGN_LEN);
|
||||
}
|
||||
|
||||
|
||||
m_csRPT1.SetCallsign(buffer->RPT1, CALLSIGN_LEN);
|
||||
m_csRPT2.SetCallsign(buffer->RPT2, CALLSIGN_LEN);
|
||||
m_csMY.SetCallsign(buffer->MY, CALLSIGN_LEN);
|
||||
@@ -165,10 +165,7 @@ CDvHeaderPacket::CDvHeaderPacket(const CM17Packet &m17) : CPacket(m17)
|
||||
m_csRPT1.SetCSModule('G');
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// virtual duplication
|
||||
|
||||
std::unique_ptr<CPacket> CDvHeaderPacket::Duplicate(void) const
|
||||
std::unique_ptr<CPacket> CDvHeaderPacket::Copy(void)
|
||||
{
|
||||
return std::unique_ptr<CPacket>(new CDvHeaderPacket(*this));
|
||||
}
|
||||
@@ -204,34 +201,3 @@ bool CDvHeaderPacket::IsValid(void) const
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// operators
|
||||
|
||||
bool CDvHeaderPacket::operator ==(const CDvHeaderPacket &Header) const
|
||||
{
|
||||
return ( (m_uiFlag1 == Header.m_uiFlag1) &&
|
||||
(m_uiFlag2 == Header.m_uiFlag2) &&
|
||||
(m_uiFlag3 == Header.m_uiFlag3) &&
|
||||
(m_csUR == Header.m_csUR) &&
|
||||
(m_csRPT1 == Header.m_csRPT1) &&
|
||||
(m_csRPT2 == Header.m_csRPT2) &&
|
||||
(m_csMY == Header.m_csMY) );
|
||||
}
|
||||
|
||||
#ifdef IMPLEMENT_CDVHEADERPACKET_CONST_CHAR_OPERATOR
|
||||
CDvHeaderPacket::operator const char *() const
|
||||
{
|
||||
char *sz = (char *)(const char *)m_sz;
|
||||
|
||||
std::sprintf(sz, "%02X %02X %02X\n%s\n%s\n%s\n%s",
|
||||
m_uiFlag1, m_uiFlag2, m_uiFlag3,
|
||||
(const char *)m_csUR,
|
||||
(const char *)m_csRPT1,
|
||||
(const char *)m_csRPT2,
|
||||
(const char *)m_csMY);
|
||||
|
||||
return m_sz;
|
||||
}
|
||||
#endif
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#include "Callsign.h"
|
||||
#include "Packet.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// implementation details
|
||||
|
||||
@@ -65,10 +65,8 @@ public:
|
||||
static unsigned int GetNetworkSize();
|
||||
void EncodeInterlinkPacket(CBuffer &buf) const;
|
||||
|
||||
// virtual duplication
|
||||
std::unique_ptr<CPacket> Duplicate(void) const;
|
||||
|
||||
// identity
|
||||
std::unique_ptr<CPacket> Copy(void);
|
||||
bool IsDvHeader(void) const { return true; }
|
||||
bool IsDvFrame(void) const { return false; }
|
||||
|
||||
@@ -94,9 +92,6 @@ public:
|
||||
void SetRpt2Callsign(const CCallsign &cs) { m_csRPT2 = cs; }
|
||||
void SetRpt2Module(char c) { m_csRPT2.SetCSModule(c); }
|
||||
|
||||
// operators
|
||||
bool operator ==(const CDvHeaderPacket &) const;
|
||||
|
||||
protected:
|
||||
// data
|
||||
uint8_t m_uiFlag1;
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
|
||||
// urfd -- The universal reflector
|
||||
// Copyright © 2021 Thomas A. Early N7TAE
|
||||
//
|
||||
// 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 3 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, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <queue>
|
||||
#include <chrono>
|
||||
#include <future>
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <ctime>
|
||||
#include <cctype>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// defines
|
||||
|
||||
//// Module configuration
|
||||
#define DSTAR_IPV4 true
|
||||
#define DMR_IPV4 true
|
||||
#define YSF_IPV4 true
|
||||
#define XLX_IPV4 true
|
||||
#define M17_IPV4 true
|
||||
#define P25_IPV4 true
|
||||
#define NXDN_IPV4 true
|
||||
#define USRP_IPV4 true
|
||||
#define URF_IPV4 true
|
||||
|
||||
|
||||
#define DSTAR_IPV6 true // QnetGateway can use IPv6
|
||||
#define DMR_IPV6 false
|
||||
#define YSF_IPV6 false
|
||||
#define XLX_IPV6 false
|
||||
#define M17_IPV6 true
|
||||
#define P25_IPV6 false
|
||||
#define NXDN_IPV6 false
|
||||
#define USRP_IPV6 false
|
||||
#define URF_IPV6 true
|
||||
|
||||
// protocols ---------------------------------------------------
|
||||
|
||||
enum class EProtocol { any, none, dextra, dplus, dcs, g3, bm, urf, dmrplus, dmrmmdvm, nxdn, p25, usrp, ysf, m17 };
|
||||
|
||||
// DExtra
|
||||
#define DEXTRA_KEEPALIVE_PERIOD 3 // in seconds
|
||||
#define DEXTRA_KEEPALIVE_TIMEOUT (DEXTRA_KEEPALIVE_PERIOD*10) // in seconds
|
||||
|
||||
// DPlus
|
||||
#define DPLUS_KEEPALIVE_PERIOD 1 // in seconds
|
||||
#define DPLUS_KEEPALIVE_TIMEOUT (DPLUS_KEEPALIVE_PERIOD*10) // in seconds
|
||||
#define DPLUS_DEFAULT_RPTR1_SUFFIX 'Y'
|
||||
|
||||
// DCS
|
||||
#define DCS_KEEPALIVE_PERIOD 1 // in seconds
|
||||
#define DCS_KEEPALIVE_TIMEOUT (DCS_KEEPALIVE_PERIOD*30) // in seconds
|
||||
|
||||
// XLX, used for BM
|
||||
#define BM_KEEPALIVE_PERIOD 1 // in seconds
|
||||
#define BM_KEEPALIVE_TIMEOUT (BM_KEEPALIVE_PERIOD*30) // in seconds
|
||||
#define BM_RECONNECT_PERIOD 5 // in seconds
|
||||
|
||||
// URF
|
||||
#define URF_KEEPALIVE_PERIOD 1 // in seconds
|
||||
#define URF_KEEPALIVE_TIMEOUT (URF_KEEPALIVE_PERIOD*30) // in seconds
|
||||
#define URF_RECONNECT_PERIOD 5 // in seconds
|
||||
|
||||
// DMRPlus (dongle)
|
||||
#define DMRPLUS_KEEPALIVE_PERIOD 1 // in seconds
|
||||
#define DMRPLUS_KEEPALIVE_TIMEOUT (DMRPLUS_KEEPALIVE_PERIOD*10) // in seconds
|
||||
#define DMRPLUS_REFLECTOR_SLOT DMR_SLOT2
|
||||
#define DMRPLUS_REFLECTOR_COLOUR 1
|
||||
|
||||
// DMRMmdvm
|
||||
#define DMRMMDVM_KEEPALIVE_PERIOD 10 // in seconds
|
||||
#define DMRMMDVM_KEEPALIVE_TIMEOUT (DMRMMDVM_KEEPALIVE_PERIOD*10) // in seconds
|
||||
#define DMRMMDVM_REFLECTOR_SLOT DMR_SLOT2
|
||||
#define DMRMMDVM_REFLECTOR_COLOUR 1
|
||||
|
||||
// YSF
|
||||
#define YSF_KEEPALIVE_PERIOD 3 // in seconds
|
||||
#define YSF_KEEPALIVE_TIMEOUT (YSF_KEEPALIVE_PERIOD*10) // in seconds
|
||||
|
||||
// M17
|
||||
#define M17_KEEPALIVE_PERIOD 3
|
||||
#define M17_KEEPALIVE_TIMEOUT (M17_KEEPALIVE_PERIOD*10)
|
||||
|
||||
// P25
|
||||
#define P25_KEEPALIVE_PERIOD 3 // in seconds
|
||||
#define P25_KEEPALIVE_TIMEOUT (P25_KEEPALIVE_PERIOD*10) // in seconds
|
||||
|
||||
// NXDN
|
||||
#define NXDN_KEEPALIVE_PERIOD 3 // in seconds
|
||||
#define NXDN_KEEPALIVE_TIMEOUT (NXDN_KEEPALIVE_PERIOD*10) // in seconds
|
||||
|
||||
// USRP
|
||||
#define USRP_KEEPALIVE_PERIOD 1 // in seconds
|
||||
#define USRP_KEEPALIVE_TIMEOUT (USRP_KEEPALIVE_PERIOD*10) // in seconds
|
||||
|
||||
// G3 Terminal
|
||||
#define G3_PRESENCE_PORT 12346 // UDP port
|
||||
#define G3_CONFIG_PORT 12345 // UDP port
|
||||
#define G3_DV_PORT 40000 // UDP port
|
||||
#define G3_KEEPALIVE_PERIOD 10 // in seconds
|
||||
#define G3_KEEPALIVE_TIMEOUT 3600 // in seconds, 1 hour
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// macros
|
||||
|
||||
#define MIN(a,b) ((a)<(b))?(a):(b)
|
||||
#define MAKEWORD(low, high) ((uint16_t)(((uint8_t)(low)) | (((uint16_t)((uint8_t)(high))) << 8)))
|
||||
#define MAKEDWORD(low, high) ((uint32_t)(((uint16_t)(low)) | (((uint32_t)((uint16_t)(high))) << 16)))
|
||||
#define LOBYTE(w) ((uint8_t)(uint16_t)(w & 0x00FF))
|
||||
#define HIBYTE(w) ((uint8_t)((((uint16_t)(w)) >> 8) & 0xFF))
|
||||
#define LOWORD(dw) ((uint16_t)(uint32_t)(dw & 0x0000FFFF))
|
||||
#define HIWORD(dw) ((uint16_t)((((uint32_t)(dw)) >> 16) & 0xFFFF))
|
||||
@@ -16,7 +16,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
|
||||
#include "G3Client.h"
|
||||
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Defines.h"
|
||||
#include "Client.h"
|
||||
|
||||
class CG3Client : public CClient
|
||||
|
||||
+17
-17
@@ -16,16 +16,14 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include "G3Client.h"
|
||||
#include "G3Protocol.h"
|
||||
#include "Reflector.h"
|
||||
#include "GateKeeper.h"
|
||||
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_icmp.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "Global.h"
|
||||
#include "G3Client.h"
|
||||
#include "G3Protocol.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -34,6 +32,10 @@
|
||||
bool CG3Protocol::Initialize(const char */*type*/, const EProtocol /*type*/, const uint16_t /*port*/, const bool /*has_ipv4*/, const bool /*has_ipv6*/)
|
||||
// everything is hard coded until ICOM gets their act together and start supporting IPv6
|
||||
{
|
||||
//config data
|
||||
m_TerminalPath.assign(g_Configure.GetString(g_Keys.files.terminal));
|
||||
const std::string ipv4address(g_Configure.GetString(g_Keys.ip.ipv4bind));
|
||||
|
||||
ReadOptions();
|
||||
|
||||
// init reflector apparent callsign
|
||||
@@ -46,7 +48,7 @@ bool CG3Protocol::Initialize(const char */*type*/, const EProtocol /*type*/, con
|
||||
//m_ReflectorCallsign.PatchCallsign(0, "XLX", 3);
|
||||
|
||||
// create our sockets
|
||||
CIp ip(AF_INET, G3_DV_PORT, LISTEN_IPV4);
|
||||
CIp ip(AF_INET, G3_DV_PORT, ipv4address.c_str());
|
||||
if ( ip.IsSet() )
|
||||
{
|
||||
if (! m_Socket4.Open(ip))
|
||||
@@ -440,14 +442,13 @@ void CG3Protocol::Task(void)
|
||||
|
||||
void CG3Protocol::HandleQueue(void)
|
||||
{
|
||||
m_Queue.Lock();
|
||||
while ( !m_Queue.empty() )
|
||||
while (! m_Queue.IsEmpty())
|
||||
{
|
||||
// supress host checks
|
||||
m_LastKeepaliveTime.start();
|
||||
|
||||
// get the packet
|
||||
auto packet = m_Queue.pop();
|
||||
auto packet = m_Queue.Pop();
|
||||
|
||||
// encode it
|
||||
CBuffer buffer;
|
||||
@@ -473,7 +474,6 @@ void CG3Protocol::HandleQueue(void)
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
}
|
||||
m_Queue.Unlock();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -672,7 +672,7 @@ void CG3Protocol::NeedReload(void)
|
||||
{
|
||||
struct stat fileStat;
|
||||
|
||||
if (::stat(TERMINALOPTIONS_PATH, &fileStat) != -1)
|
||||
if (::stat(m_TerminalPath.c_str(), &fileStat) != -1)
|
||||
{
|
||||
if (m_LastModTime != fileStat.st_mtime)
|
||||
{
|
||||
@@ -701,7 +701,7 @@ void CG3Protocol::ReadOptions(void)
|
||||
int opts = 0;
|
||||
|
||||
|
||||
std::ifstream file(TERMINALOPTIONS_PATH);
|
||||
std::ifstream file(m_TerminalPath.c_str());
|
||||
if (file.is_open())
|
||||
{
|
||||
m_GwAddress = 0u;
|
||||
@@ -742,12 +742,12 @@ void CG3Protocol::ReadOptions(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << "G3 handler loaded " << opts << " options from file " << TERMINALOPTIONS_PATH << std::endl;
|
||||
std::cout << "G3 handler loaded " << opts << " options from file " << m_TerminalPath << std::endl;
|
||||
file.close();
|
||||
|
||||
struct stat fileStat;
|
||||
|
||||
if (::stat(TERMINALOPTIONS_PATH, &fileStat) != -1)
|
||||
if (::stat(m_TerminalPath.c_str(), &fileStat) != -1)
|
||||
{
|
||||
m_LastModTime = fileStat.st_mtime;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "Defines.h"
|
||||
#include "Timer.h"
|
||||
#include "SEProtocol.h"
|
||||
#include "DVHeaderPacket.h"
|
||||
@@ -117,4 +119,5 @@ protected:
|
||||
uint32_t m_GwAddress;
|
||||
std::string m_Modules;
|
||||
time_t m_LastModTime;
|
||||
std::string m_TerminalPath;
|
||||
};
|
||||
+17
-25
@@ -16,14 +16,9 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
|
||||
#include "Timer.h"
|
||||
#include "GateKeeper.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CGateKeeper g_GateKeeper;
|
||||
|
||||
#include "Global.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor
|
||||
@@ -49,9 +44,9 @@ bool CGateKeeper::Init(void)
|
||||
{
|
||||
|
||||
// load lists from files
|
||||
m_NodeWhiteList.LoadFromFile(WHITELIST_PATH);
|
||||
m_NodeBlackList.LoadFromFile(BLACKLIST_PATH);
|
||||
m_PeerList.LoadFromFile(INTERLINKLIST_PATH);
|
||||
m_NodeWhiteList.LoadFromFile(g_Configure.GetString(g_Keys.files.white));
|
||||
m_NodeBlackList.LoadFromFile(g_Configure.GetString(g_Keys.files.black));
|
||||
m_PeerList.LoadFromFile(g_Configure.GetString(g_Keys.files.interlink));
|
||||
|
||||
// reset run flag
|
||||
keep_running = true;
|
||||
@@ -92,9 +87,7 @@ bool CGateKeeper::MayLink(const CCallsign &callsign, const CIp &ip, EProtocol pr
|
||||
case EProtocol::p25:
|
||||
case EProtocol::usrp:
|
||||
case EProtocol::nxdn:
|
||||
#ifndef NO_G3
|
||||
case EProtocol::g3:
|
||||
#endif
|
||||
// first check is IP & callsigned listed OK
|
||||
ok &= IsNodeListedOk(callsign, ip);
|
||||
// todo: then apply any protocol specific authorisation for the operation
|
||||
@@ -141,9 +134,7 @@ bool CGateKeeper::MayTransmit(const CCallsign &callsign, const CIp &ip, const EP
|
||||
case EProtocol::p25:
|
||||
case EProtocol::nxdn:
|
||||
case EProtocol::usrp:
|
||||
#ifndef NO_G3
|
||||
case EProtocol::g3:
|
||||
#endif
|
||||
// first check is IP & callsigned listed OK
|
||||
ok = ok && IsNodeListedOk(callsign, ip, module);
|
||||
// todo: then apply any protocol specific authorisation for the operation
|
||||
@@ -213,17 +204,20 @@ bool CGateKeeper::IsNodeListedOk(const CCallsign &callsign, const CIp &ip, char
|
||||
{
|
||||
// first check if callsign is in white list
|
||||
// note if white list is empty, everybody is authorized
|
||||
const_cast<CCallsignList &>(m_NodeWhiteList).Lock();
|
||||
m_NodeWhiteList.Lock();
|
||||
if ( !m_NodeWhiteList.empty() )
|
||||
{
|
||||
ok = m_NodeWhiteList.IsCallsignListedWithWildcard(callsign, module);
|
||||
}
|
||||
const_cast<CCallsignList &>(m_NodeWhiteList).Unlock();
|
||||
m_NodeWhiteList.Unlock();
|
||||
|
||||
// then check if not blacklisted
|
||||
const_cast<CCallsignList &>(m_NodeBlackList).Lock();
|
||||
ok &= !m_NodeBlackList.IsCallsignListedWithWildcard(callsign);
|
||||
const_cast<CCallsignList &>(m_NodeBlackList).Unlock();
|
||||
if (ok)
|
||||
{
|
||||
m_NodeBlackList.Lock();
|
||||
ok = !m_NodeBlackList.IsCallsignListedWithWildcard(callsign);
|
||||
m_NodeBlackList.Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// done
|
||||
@@ -241,12 +235,12 @@ bool CGateKeeper::IsPeerListedOk(const CCallsign &callsign, const CIp &ip, char
|
||||
if ( ok )
|
||||
{
|
||||
// look for an exact match in the list
|
||||
const_cast<CPeerCallsignList &>(m_PeerList).Lock();
|
||||
m_PeerList.Lock();
|
||||
if ( !m_PeerList.empty() )
|
||||
{
|
||||
ok = m_PeerList.IsCallsignListed(callsign, module);
|
||||
}
|
||||
const_cast<CPeerCallsignList &>(m_PeerList).Unlock();
|
||||
m_PeerList.Unlock();
|
||||
}
|
||||
|
||||
// done
|
||||
@@ -263,12 +257,12 @@ bool CGateKeeper::IsPeerListedOk(const CCallsign &callsign, const CIp &ip, char
|
||||
if ( ok )
|
||||
{
|
||||
// look for an exact match in the list
|
||||
const_cast<CPeerCallsignList &>(m_PeerList).Lock();
|
||||
m_PeerList.Lock();
|
||||
if ( !m_PeerList.empty() )
|
||||
{
|
||||
ok = m_PeerList.IsCallsignListed(callsign, modules);
|
||||
}
|
||||
const_cast<CPeerCallsignList &>(m_PeerList).Unlock();
|
||||
m_PeerList.Unlock();
|
||||
}
|
||||
|
||||
// done
|
||||
@@ -300,10 +294,8 @@ const std::string CGateKeeper::ProtocolName(const EProtocol p) const
|
||||
return "USRP";
|
||||
case EProtocol::bm:
|
||||
return "Brandmeister";
|
||||
#ifndef NO_G3
|
||||
case EProtocol::g3:
|
||||
return "Icom G3";
|
||||
#endif
|
||||
default:
|
||||
return "NONE";
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Main.h"
|
||||
#include "Defines.h"
|
||||
#include "Callsign.h"
|
||||
#include "IP.h"
|
||||
#include "CallsignList.h"
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// Copyright © 2019 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
|
||||
// urfd -- The universal reflector
|
||||
// Copyright © 2021 Thomas A. Early N7TAE
|
||||
// Copyright © 2023 Thomas A. Early N7TAE
|
||||
//
|
||||
// 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
|
||||
@@ -16,25 +14,20 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
#include "Reflector.h"
|
||||
#include "GateKeeper.h"
|
||||
#include "Configure.h"
|
||||
#include "Version.h"
|
||||
#include "LookupDmr.h"
|
||||
#include "LookupNxdn.h"
|
||||
#include "LookupYsf.h"
|
||||
#include "JsonKeys.h"
|
||||
|
||||
#include "YSFNodeDir.h"
|
||||
|
||||
class CYsfNodeDirHttp : public CYsfNodeDir
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CYsfNodeDirHttp() {}
|
||||
|
||||
// destructor
|
||||
~CYsfNodeDirHttp() {}
|
||||
|
||||
// refresh
|
||||
bool LoadContent(CBuffer *);
|
||||
bool RefreshContent(const CBuffer &);
|
||||
|
||||
protected:
|
||||
// reload helpers
|
||||
bool NeedReload(void) { return true; }
|
||||
bool HttpGet(const char *, const char *, int, CBuffer *);
|
||||
};
|
||||
extern CReflector g_Reflector;
|
||||
extern CGateKeeper g_GateKeeper;
|
||||
extern CConfigure g_Configure;
|
||||
extern CVersion g_Version;
|
||||
extern CLookupDmr g_LDid;
|
||||
extern CLookupNxdn g_LNid;
|
||||
extern CLookupYsf g_LYtr;
|
||||
extern SJsonKeys g_Keys;
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2023 by Thomas A. Early N7TAE
|
||||
*
|
||||
* 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 <string>
|
||||
|
||||
#pragma once
|
||||
|
||||
// configuration key names
|
||||
struct SJsonKeys {
|
||||
struct PORTONLY { const std::string port; }
|
||||
dcs { "DCSPort" },
|
||||
dextra { "DExtraPort" },
|
||||
dmrplus { "DMRPlusPort" },
|
||||
dplus { "DPlusPort" },
|
||||
m17 { "M17Port" },
|
||||
urf { "URFPort" };
|
||||
|
||||
struct G3 { const std::string enable; }
|
||||
g3 { "G3Enable" };
|
||||
|
||||
struct BM { const std::string enable, port; }
|
||||
bm { "bmEnable", "bmPort" };
|
||||
|
||||
struct MMDVM { const std::string port, defaultid; }
|
||||
mmdvm { "MMDVMPort", "mmdvmdefaultid" };
|
||||
|
||||
struct NAMES { const std::string callsign, email, country, sponsor; }
|
||||
names { "Callsign", "SysopEmail", "Country", "Sponsor" };
|
||||
|
||||
struct IP { const std::string ipv4bind, ipv4address, ipv6bind, ipv6address, transcoder; }
|
||||
ip { "ipv4bind", "IPv4Address", "ipv6bind", "IPv6Address", "tcaddress" };
|
||||
|
||||
struct MODULES { const std::string modules, tcmodules, descriptor[26]; }
|
||||
modules { "Modules", "TranscodedModules",
|
||||
"DescriptionA", "DescriptionB", "DescriptionC", "DescriptionD", "DescriptionE", "DescriptionF", "DescriptionG", "DescriptionH", "DescriptionI", "DescriptionJ", "DescriptionK", "DescriptionL", "DescriptionM", "DescriptionN", "DescriptionO", "DescriptionP", "DescriptionQ", "DescriptionR", "DescriptionS", "DescriptionT", "DescriptionU", "DescriptionV", "DescriptionW", "DescriptionX", "DescriptionY", "DescriptionZ" };
|
||||
|
||||
struct USRP { const std::string enable, ip, txport, rxport, module, callsign, filepath; }
|
||||
usrp { "usrpEnable", "usrpIpAddress", "urspTxPort", "usrpRxPort", "usrpModule", "usrpCallsign", "usrpFilePath" };
|
||||
|
||||
struct P25NXDN { const std::string port, autolinkmod, reflectorid; }
|
||||
p25 { "P25Port", "P25AutolinkMod", "P25ReflectorID" },
|
||||
nxdn { "NXDNPort", "NXDNAutolinkMod", "NXDNReflectorID" };
|
||||
|
||||
struct YSF { const std::string port, autolinkmod, defaulttxfreq, defaultrxfreq;
|
||||
struct YSLREG { const std::string id, name, description; } ysfreflectordb; }
|
||||
ysf { "YSFPort", "YSFAutoLinkMod", "YSFDefaultTxFreq", "YSFDefaultRxFreq",
|
||||
{ "ysfrefdbid", "ysfrefdbname", "ysfrefdbdesc" } };
|
||||
|
||||
struct DB { const std::string url, mode, refreshmin, filepath; }
|
||||
dmriddb { "dmrIdDbUrl", "dmrIdDbMode", "dmrIdDbRefresh", "dmrIdDbFilePath" },
|
||||
nxdniddb { "nxdnIdDbUrl", "nxdnIdDbMode", "nxdnIdDbRefresh", "nxdnIdDbFilePath" },
|
||||
ysftxrxdb { "ysfIdDbUrl", "ysfIdDbMode", "ysfIdDbRefresh", "ysfIdDbFilePath" };
|
||||
|
||||
struct FILES { const std::string pid, xml, json, white, black, interlink, terminal; }
|
||||
files { "pidFilePath", "xmlFilePath", "jsonFilePath", "whitelistFilePath", "blacklistFilePath", "interlinkFilePath", "g3TerminalFilePath" };
|
||||
};
|
||||
@@ -0,0 +1,125 @@
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
|
||||
// urfd -- The universal reflector
|
||||
// Copyright © 2023 Thomas A. Early N7TAE
|
||||
//
|
||||
// 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 3 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, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <fstream>
|
||||
#include <unordered_map>
|
||||
#include <thread>
|
||||
#include <sys/stat.h>
|
||||
#include "CurlGet.h"
|
||||
#include "Lookup.h"
|
||||
|
||||
void CLookup::LookupClose()
|
||||
{
|
||||
keep_running = false;
|
||||
if (m_Future.valid())
|
||||
m_Future.get();
|
||||
}
|
||||
|
||||
std::time_t CLookup::GetLastModTime()
|
||||
{
|
||||
struct stat fileStat;
|
||||
if(0 == stat(m_Path.c_str(), &fileStat))
|
||||
{
|
||||
return fileStat.st_mtime;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CLookup::LookupInit()
|
||||
{
|
||||
LoadParameters();
|
||||
|
||||
m_Future = std::async(std::launch::async, &CLookup::Thread, this);
|
||||
}
|
||||
|
||||
void CLookup::Thread()
|
||||
{
|
||||
const unsigned long wait_cycles = m_Refresh * 6u; // the number of while loops in m_Refresh
|
||||
unsigned long count = 0;
|
||||
while (keep_running)
|
||||
{
|
||||
std::stringstream ss;
|
||||
bool http_loaded = false;
|
||||
bool file_loaded = false;
|
||||
|
||||
// load http section first, if configured and m_Refresh minutes have lapsed
|
||||
// on the first pass through this while loop (count == 0)
|
||||
if (ERefreshType::file != m_Type && 0ul == count++ % wait_cycles)
|
||||
{
|
||||
// if SIG_INT was received at this point in time,
|
||||
// in might take a bit more than 10 seconds to soft close
|
||||
http_loaded = LoadContentHttp(ss);
|
||||
}
|
||||
|
||||
// load the file if http was loaded or if we haven't loaded since the last mod time
|
||||
if (ERefreshType::http != m_Type)
|
||||
{
|
||||
if (http_loaded || m_LastLoadTime < GetLastModTime())
|
||||
{
|
||||
file_loaded = LoadContentFile(ss);
|
||||
time(&m_LastLoadTime);
|
||||
}
|
||||
}
|
||||
|
||||
// now update the map(s) if anything was loaded
|
||||
if (http_loaded || file_loaded)
|
||||
{
|
||||
Lock();
|
||||
// if m_Type == ERefreshType::both, and if something was deleted from the file,
|
||||
// it won't be purged from the map(s) until http is loaded
|
||||
// It would be a lot of work (iterating on an unordered_map) to do otherwise!
|
||||
if (http_loaded || ERefreshType::file == m_Type)
|
||||
ClearContents();
|
||||
UpdateContent(ss, Eaction::normal);
|
||||
Unlock();
|
||||
}
|
||||
|
||||
// now wait for 10 seconds
|
||||
std::this_thread::sleep_for(std::chrono::seconds(10));
|
||||
}
|
||||
}
|
||||
|
||||
bool CLookup::LoadContentHttp(std::stringstream &ss)
|
||||
{
|
||||
CCurlGet get;
|
||||
auto code = get.GetURL(m_Url, ss);
|
||||
return CURLE_OK == code;
|
||||
}
|
||||
|
||||
bool CLookup::LoadContentFile(std::stringstream &ss)
|
||||
{
|
||||
bool rval = false;
|
||||
std::ifstream file(m_Path);
|
||||
if ( file )
|
||||
{
|
||||
ss << file.rdbuf();
|
||||
file.close();
|
||||
rval = true;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
bool CLookup::Utility(Eaction action, Esource source)
|
||||
{
|
||||
std::stringstream ss;
|
||||
LoadParameters();
|
||||
auto rval = (Esource::http == source) ? LoadContentHttp(ss) : LoadContentFile(ss);
|
||||
if (rval)
|
||||
UpdateContent(ss, action);
|
||||
return rval;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
|
||||
// urfd -- The universal reflector
|
||||
// Copyright © 2021 Thomas A. Early N7TAE
|
||||
// Copyright © 2023 Thomas A. Early N7TAE
|
||||
//
|
||||
// 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
|
||||
@@ -18,68 +18,68 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include "Buffer.h"
|
||||
#include <atomic>
|
||||
#include <future>
|
||||
#include <iostream>
|
||||
#include "Callsign.h"
|
||||
#include "Configure.h"
|
||||
|
||||
enum class Eaction { normal, parse, error_only };
|
||||
enum class Esource { http, file };
|
||||
|
||||
// compare function for std::map::find
|
||||
|
||||
struct CDmridDirCallsignCompare
|
||||
struct CCallsignHash
|
||||
{
|
||||
bool operator() (const CCallsign &cs1, const CCallsign &cs2) const
|
||||
{ return cs1.HasLowerCallsign(cs2);}
|
||||
std::size_t operator() (const UCallsign &ucs) const
|
||||
{
|
||||
std::hash<uint64_t> hash;
|
||||
return hash(ucs.l);
|
||||
}
|
||||
};
|
||||
|
||||
struct CCallsignEqual
|
||||
{
|
||||
bool operator() (const UCallsign &ucs1, const UCallsign &ucs2) const
|
||||
{
|
||||
return ucs1.l == ucs2.l;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CDmridDir
|
||||
class CLookup
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CDmridDir();
|
||||
CLookup() : keep_running(true), m_LastLoadTime(0) {}
|
||||
|
||||
// destructor
|
||||
~CDmridDir();
|
||||
|
||||
// init & close
|
||||
virtual bool Init(void);
|
||||
virtual void Close(void);
|
||||
void LookupInit();
|
||||
void LookupClose();
|
||||
|
||||
// locks
|
||||
void Lock(void) { m_Mutex.lock(); }
|
||||
void Unlock(void) { m_Mutex.unlock(); }
|
||||
|
||||
// refresh
|
||||
virtual bool LoadContent(CBuffer *) { return false; }
|
||||
virtual bool RefreshContent(const CBuffer &) { return false; }
|
||||
|
||||
// find
|
||||
const CCallsign *FindCallsign(uint32_t);
|
||||
uint32_t FindDmrid(const CCallsign &);
|
||||
void Lock(void) { m_Mutex.lock(); }
|
||||
void Unlock(void) { m_Mutex.unlock(); }
|
||||
bool Utility(Eaction action, Esource source);
|
||||
|
||||
protected:
|
||||
// thread
|
||||
std::time_t GetLastModTime();
|
||||
virtual void LoadParameters() = 0;
|
||||
virtual void ClearContents() = 0;
|
||||
void Thread();
|
||||
|
||||
// reload helpers
|
||||
bool Reload(void);
|
||||
virtual bool NeedReload(void) { return false; }
|
||||
bool IsValidDmrid(const char *);
|
||||
// refresh
|
||||
bool LoadContentHttp(std::stringstream &ss);
|
||||
bool LoadContentFile(std::stringstream &ss);
|
||||
virtual void UpdateContent(std::stringstream &ss, Eaction action) = 0;
|
||||
|
||||
protected:
|
||||
// data
|
||||
std::map <uint32_t, CCallsign> m_CallsignMap;
|
||||
std::map <CCallsign, uint32_t, CDmridDirCallsignCompare> m_DmridMap;
|
||||
|
||||
// Lock()
|
||||
std::mutex m_Mutex;
|
||||
ERefreshType m_Type;
|
||||
unsigned m_Refresh;
|
||||
std::string m_Path, m_Url;
|
||||
std::time_t m_LastLoadTime;
|
||||
|
||||
// thread
|
||||
std::atomic<bool> keep_running;
|
||||
std::future<void> m_Future;
|
||||
|
||||
};
|
||||
@@ -0,0 +1,103 @@
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
|
||||
// urfd -- The universal reflector
|
||||
// Copyright © 2023 Thomas A. Early N7TAE
|
||||
//
|
||||
// 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 3 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, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include "Global.h"
|
||||
|
||||
void CLookupDmr::ClearContents()
|
||||
{
|
||||
m_CallsignMap.clear();
|
||||
m_DmridMap.clear();
|
||||
}
|
||||
|
||||
void CLookupDmr::LoadParameters()
|
||||
{
|
||||
m_Type = g_Configure.GetRefreshType(g_Keys.dmriddb.mode);
|
||||
m_Refresh = g_Configure.GetUnsigned(g_Keys.dmriddb.refreshmin);
|
||||
m_Path.assign(g_Configure.GetString(g_Keys.dmriddb.filepath));
|
||||
m_Url.assign(g_Configure.GetString(g_Keys.dmriddb.url));
|
||||
}
|
||||
|
||||
uint32_t CLookupDmr::FindDmrid(const UCallsign &ucs) const
|
||||
{
|
||||
auto found = m_DmridMap.find(ucs);
|
||||
if ( found != m_DmridMap.end() )
|
||||
{
|
||||
return (found->second);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const UCallsign *CLookupDmr::FindCallsign(const uint32_t dmrid) const
|
||||
{
|
||||
auto found = m_CallsignMap.find(dmrid);
|
||||
if ( found != m_CallsignMap.end() )
|
||||
{
|
||||
return &(found->second);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CLookupDmr::UpdateContent(std::stringstream &ss, Eaction action)
|
||||
{
|
||||
std::string line;
|
||||
while (std::getline(ss, line))
|
||||
{
|
||||
bool failed = true;
|
||||
auto l = atol(line.c_str()); // no throw guarantee
|
||||
if (0L < l && l <= 9999999L)
|
||||
{
|
||||
auto id = uint32_t(l);
|
||||
auto p1 = line.find(';');
|
||||
if (std::string::npos != p1)
|
||||
{
|
||||
auto p2 = line.find(';', ++p1);
|
||||
if (std::string::npos != p2)
|
||||
{
|
||||
const auto cs_str(line.substr(p1, p2-p1));
|
||||
CCallsign cs;
|
||||
cs.SetCallsign(cs_str, false);
|
||||
if (cs.IsValid())
|
||||
{
|
||||
failed = false;
|
||||
if (Eaction::normal == action)
|
||||
{
|
||||
auto key = cs.GetKey();
|
||||
m_DmridMap[key] = id;
|
||||
m_CallsignMap[id] = key;
|
||||
}
|
||||
else if (Eaction::parse == action)
|
||||
{
|
||||
std::cout << id << ';' << cs_str << ";\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Eaction::error_only == action && failed)
|
||||
{
|
||||
std::cout << line << '\n';
|
||||
}
|
||||
}
|
||||
if (Eaction::normal == action)
|
||||
std::cout << "DMR Id database size: " << m_DmridMap.size() << std::endl;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
|
||||
// urfd -- The universal reflector
|
||||
// Copyright © 2021 Thomas A. Early N7TAE
|
||||
// Copyright © 2023 Thomas A. Early N7TAE
|
||||
//
|
||||
// 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
|
||||
@@ -18,23 +18,21 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "NXDNIdDir.h"
|
||||
#include "Lookup.h"
|
||||
|
||||
class CNXDNidDirHttp : public CNXDNidDir
|
||||
class CLookupDmr : public CLookup
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CNXDNidDirHttp() {}
|
||||
|
||||
// destructor
|
||||
~CNXDNidDirHttp() {}
|
||||
|
||||
// refresh
|
||||
bool LoadContent(CBuffer *);
|
||||
bool RefreshContent(const CBuffer &);
|
||||
~CLookupDmr() {}
|
||||
uint32_t FindDmrid(const UCallsign &ucs) const;
|
||||
const UCallsign *FindCallsign(uint32_t dmrid) const;
|
||||
|
||||
protected:
|
||||
// reload helpers
|
||||
bool NeedReload(void) { return true; }
|
||||
bool HttpGet(const char *, const char *, int, CBuffer *);
|
||||
void ClearContents();
|
||||
void LoadParameters();
|
||||
void UpdateContent(std::stringstream &ss, Eaction action);
|
||||
|
||||
private:
|
||||
std::unordered_map<uint32_t, UCallsign> m_CallsignMap;
|
||||
std::unordered_map<UCallsign, uint32_t, CCallsignHash, CCallsignEqual> m_DmridMap;
|
||||
};
|
||||
@@ -0,0 +1,103 @@
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
|
||||
// urfd -- The universal reflector
|
||||
// Copyright © 2023 Thomas A. Early N7TAE
|
||||
//
|
||||
// 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 3 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, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <iostream>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include "Global.h"
|
||||
|
||||
void CLookupNxdn::ClearContents()
|
||||
{
|
||||
m_CallsignMap.clear();
|
||||
m_NxdnidMap.clear();
|
||||
}
|
||||
|
||||
void CLookupNxdn::LoadParameters()
|
||||
{
|
||||
m_Type = g_Configure.GetRefreshType(g_Keys.nxdniddb.mode);
|
||||
m_Refresh = g_Configure.GetUnsigned(g_Keys.nxdniddb.refreshmin);
|
||||
m_Path.assign(g_Configure.GetString(g_Keys.nxdniddb.filepath));
|
||||
m_Url.assign(g_Configure.GetString(g_Keys.nxdniddb.url));
|
||||
}
|
||||
|
||||
const UCallsign *CLookupNxdn::FindCallsign(uint16_t nxdnid) const
|
||||
{
|
||||
auto found = m_CallsignMap.find(nxdnid);
|
||||
if ( found != m_CallsignMap.end() )
|
||||
{
|
||||
return &(found->second);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint16_t CLookupNxdn::FindNXDNid(const UCallsign &ucs) const
|
||||
{
|
||||
auto found = m_NxdnidMap.find(ucs);
|
||||
if ( found != m_NxdnidMap.end() )
|
||||
{
|
||||
return found->second;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CLookupNxdn::UpdateContent(std::stringstream &ss, Eaction action)
|
||||
{
|
||||
std::string line;
|
||||
while (std::getline(ss, line))
|
||||
{
|
||||
bool failed = true;
|
||||
auto l = atol(line.c_str()); // no throw guarantee
|
||||
if (0 < l && l < 0x10000)
|
||||
{
|
||||
auto id = uint32_t(l);
|
||||
auto p1 = line.find(',');
|
||||
if (std::string::npos != p1)
|
||||
{
|
||||
auto p2 = line.find(',', ++p1);
|
||||
if (std::string::npos != p2)
|
||||
{
|
||||
const auto cs_str = line.substr(p1, p2-p1);
|
||||
CCallsign cs;
|
||||
cs.SetCallsign(cs_str, false);
|
||||
if (cs.IsValid())
|
||||
{
|
||||
failed = false;
|
||||
if (Eaction::normal == action)
|
||||
{
|
||||
auto key = cs.GetKey();
|
||||
m_NxdnidMap[key] = id;
|
||||
m_CallsignMap[id] = key;
|
||||
}
|
||||
else if (Eaction::parse == action)
|
||||
{
|
||||
std::cout << id << ',' << cs_str << ",\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Eaction::error_only == action && failed)
|
||||
{
|
||||
std::cout << line << '\n';
|
||||
}
|
||||
}
|
||||
if (Eaction::normal == action)
|
||||
std::cout << "NXDN Id database size: " << m_NxdnidMap.size() << std::endl;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
|
||||
// urfd -- The universal reflector
|
||||
// Copyright © 2021 Thomas A. Early N7TAE
|
||||
// Copyright © 2023 Thomas A. Early N7TAE
|
||||
//
|
||||
// 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
|
||||
@@ -18,23 +18,19 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "DMRIdDir.h"
|
||||
#include "Lookup.h"
|
||||
|
||||
class CDmridDirHttp : public CDmridDir
|
||||
class CLookupNxdn : public CLookup
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CDmridDirHttp() {}
|
||||
|
||||
// destructor
|
||||
~CDmridDirHttp() {}
|
||||
|
||||
// refresh
|
||||
bool LoadContent(CBuffer *);
|
||||
bool RefreshContent(const CBuffer &);
|
||||
|
||||
uint16_t FindNXDNid(const UCallsign &ucs) const;
|
||||
const UCallsign *FindCallsign(const uint16_t id) const;
|
||||
protected:
|
||||
// reload helpers
|
||||
bool NeedReload(void) { return true; }
|
||||
bool HttpGet(const char *, const char *, int, CBuffer *);
|
||||
void ClearContents();
|
||||
void LoadParameters();
|
||||
void UpdateContent(std::stringstream &ss, Eaction action);
|
||||
|
||||
private:
|
||||
std::unordered_map <uint32_t, UCallsign> m_CallsignMap;
|
||||
std::unordered_map <UCallsign, uint32_t, CCallsignHash, CCallsignEqual> m_NxdnidMap;
|
||||
};
|
||||
@@ -0,0 +1,89 @@
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
|
||||
// urfd -- The universal reflector
|
||||
// Copyright © 2023 Thomas A. Early N7TAE
|
||||
//
|
||||
// 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 3 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, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include "Global.h"
|
||||
|
||||
void CLookupYsf::ClearContents()
|
||||
{
|
||||
m_map.clear();
|
||||
}
|
||||
|
||||
void CLookupYsf::LoadParameters()
|
||||
{
|
||||
m_Type = g_Configure.GetRefreshType(g_Keys.ysftxrxdb.mode);
|
||||
m_Refresh = g_Configure.GetUnsigned(g_Keys.ysftxrxdb.refreshmin);
|
||||
m_Path.assign(g_Configure.GetString(g_Keys.ysftxrxdb.filepath));
|
||||
m_Url.assign(g_Configure.GetString(g_Keys.ysftxrxdb.url));
|
||||
m_DefaultTx = g_Configure.GetUnsigned(g_Keys.ysf.defaulttxfreq);
|
||||
m_DefaultRx = g_Configure.GetUnsigned(g_Keys.ysf.defaultrxfreq);
|
||||
}
|
||||
|
||||
void CLookupYsf::UpdateContent(std::stringstream &ss, Eaction action)
|
||||
{
|
||||
std::string line;
|
||||
while (std::getline(ss, line))
|
||||
{
|
||||
CCallsign cs;
|
||||
std::string cs_str, tx_str, rx_str;
|
||||
std::istringstream iss(line);
|
||||
std::getline(iss, cs_str, ';');
|
||||
std::getline(iss, tx_str, ';');
|
||||
std::getline(iss, rx_str, ';');
|
||||
cs.SetCallsign(cs_str, false);
|
||||
auto ltx = atoll(tx_str.c_str());
|
||||
auto lrx = atoll(rx_str.c_str());
|
||||
unsigned x = sizeof(lrx);
|
||||
if (ltx > 40000000 && ltx < 0x100000000 && lrx > 40000000 && lrx < 0x100000000 && cs.IsValid())
|
||||
{
|
||||
if (Eaction::parse == action)
|
||||
{
|
||||
std::cout << cs_str << ';' << tx_str << ';' << rx_str << ";\n";
|
||||
}
|
||||
else if (Eaction::normal == action)
|
||||
{
|
||||
m_map[cs.GetKey()] = CYsfNode(ltx, lrx);
|
||||
}
|
||||
}
|
||||
else if (Eaction::error_only == action)
|
||||
{
|
||||
std::cout << line << '\n';
|
||||
}
|
||||
}
|
||||
if (Eaction::normal == action)
|
||||
std::cout << "YSF frequency database size now is " << m_map.size() << std::endl;
|
||||
}
|
||||
|
||||
void CLookupYsf::FindFrequencies(const CCallsign &cs, uint32_t &txfreq, uint32_t &rxfreq)
|
||||
{
|
||||
auto found = m_map.find(cs.GetKey());
|
||||
if (found != m_map.end())
|
||||
{
|
||||
txfreq = found->second.GetTxFrequency();
|
||||
rxfreq = found->second.GetRxFrequency();
|
||||
}
|
||||
else
|
||||
{
|
||||
txfreq = m_DefaultTx;
|
||||
rxfreq = m_DefaultRx;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
|
||||
// urfd -- The universal reflector
|
||||
// Copyright © 2021 Thomas A. Early N7TAE
|
||||
// Copyright © 2023 Thomas A. Early N7TAE
|
||||
//
|
||||
// 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
|
||||
@@ -18,30 +18,23 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "NXDNIdDir.h"
|
||||
#include "YSFNode.h"
|
||||
#include "Lookup.h"
|
||||
|
||||
class CNXDNidDirFile : public CNXDNidDir
|
||||
using CsNodeMap = std::unordered_map<UCallsign, CYsfNode, CCallsignHash, CCallsignEqual>;
|
||||
|
||||
class CLookupYsf : public CLookup
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CNXDNidDirFile();
|
||||
|
||||
// destructor
|
||||
~CNXDNidDirFile() {}
|
||||
|
||||
// init & close
|
||||
bool Init(void);
|
||||
|
||||
// refresh
|
||||
bool LoadContent(CBuffer *);
|
||||
bool RefreshContent(const CBuffer &);
|
||||
void FindFrequencies(const CCallsign &, uint32_t &, uint32_t &);
|
||||
|
||||
protected:
|
||||
// reload helpers
|
||||
bool NeedReload(void);
|
||||
bool GetLastModTime(time_t *);
|
||||
void ClearContents();
|
||||
void LoadParameters();
|
||||
void UpdateContent(std::stringstream &ss, Eaction action);
|
||||
|
||||
protected:
|
||||
// data
|
||||
time_t m_LastModTime;
|
||||
private:
|
||||
CsNodeMap m_map;
|
||||
|
||||
unsigned m_DefaultTx, m_DefaultRx;
|
||||
};
|
||||
@@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
|
||||
#include "M17Client.h"
|
||||
|
||||
|
||||
|
||||
@@ -16,15 +16,9 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Defines.h"
|
||||
#include "Client.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// define
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CM17Client : public CClient
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -84,11 +84,6 @@ void CM17Packet::SetCRC(uint16_t crc)
|
||||
m17.crc = htons(crc);
|
||||
}
|
||||
|
||||
std::unique_ptr<CM17Packet> CM17Packet::Duplicate(void) const
|
||||
{
|
||||
return std::unique_ptr<CM17Packet>(new CM17Packet(*this));
|
||||
}
|
||||
|
||||
bool CM17Packet::IsLastPacket() const
|
||||
{
|
||||
return ((0x8000u & ntohs(m17.framenumber)) == 0x8000u);
|
||||
|
||||
@@ -69,7 +69,6 @@ public:
|
||||
uint16_t GetStreamId() const;
|
||||
uint16_t GetCRC() const;
|
||||
void SetCRC(uint16_t crc);
|
||||
std::unique_ptr<CM17Packet> Duplicate(void) const;
|
||||
bool IsLastPacket() const;
|
||||
|
||||
private:
|
||||
|
||||
@@ -16,13 +16,12 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "M17Client.h"
|
||||
#include "M17Protocol.h"
|
||||
#include "M17Packet.h"
|
||||
#include "Reflector.h"
|
||||
#include "GateKeeper.h"
|
||||
#include "Global.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// operation
|
||||
@@ -222,11 +221,10 @@ void CM17Protocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
|
||||
|
||||
void CM17Protocol::HandleQueue(void)
|
||||
{
|
||||
m_Queue.Lock();
|
||||
while ( !m_Queue.empty() )
|
||||
while (! m_Queue.IsEmpty())
|
||||
{
|
||||
// get the packet
|
||||
auto packet = m_Queue.pop();
|
||||
auto packet = m_Queue.Pop();
|
||||
|
||||
// get our sender's id
|
||||
const auto module = packet->GetPacketModule();
|
||||
@@ -271,7 +269,6 @@ void CM17Protocol::HandleQueue(void)
|
||||
m_StreamsCache[module].m_iSeqCounter++;
|
||||
}
|
||||
}
|
||||
m_Queue.Unlock();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Defines.h"
|
||||
#include "Timer.h"
|
||||
#include "Protocol.h"
|
||||
#include "DVHeaderPacket.h"
|
||||
|
||||
+152
-20
@@ -16,53 +16,56 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
#include "Reflector.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "Global.h"
|
||||
|
||||
#ifndef UTILITY
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// global objects
|
||||
|
||||
SJsonKeys g_Keys;
|
||||
CReflector g_Reflector;
|
||||
CGateKeeper g_GateKeeper;
|
||||
CConfigure g_Configure;
|
||||
CVersion g_Version(3,0,1); // The major byte should only change if the interlink packet changes!
|
||||
CLookupDmr g_LDid;
|
||||
CLookupNxdn g_LNid;
|
||||
CLookupYsf g_LYtr;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// function declaration
|
||||
|
||||
#include "Users.h"
|
||||
|
||||
int main()
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const std::string cs(CALLSIGN);
|
||||
if ((cs.size() != 6) || cs.compare(0, 3, "URF"))
|
||||
if (argc != 2)
|
||||
{
|
||||
std::cerr << "Malformed reflector callsign: '" << cs << "', aborting!" << std::endl;
|
||||
std::cerr << "No configuration file specifed! Usage: " << argv[0] << " /pathname/to/configuration/file" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (g_Configure.ReadData(argv[1]))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
std::cout << "IPv4 binding address is '" << g_Configure.GetString(g_Keys.ip.ipv4bind) << "'" << std::endl;
|
||||
// remove pidfile
|
||||
remove(PIDFILE_PATH);
|
||||
const std::string pidpath(g_Configure.GetString(g_Keys.files.pid));
|
||||
const std::string callsign(g_Configure.GetString(g_Keys.names.callsign));
|
||||
remove(pidpath.c_str());
|
||||
|
||||
// splash
|
||||
std::cout << "Starting " << cs << " " << VERSION_MAJOR << "." << VERSION_MINOR << "." << VERSION_REVISION << std::endl << std::endl;
|
||||
|
||||
#ifdef TRANSCODER_IS_REMOTE
|
||||
g_Reflector.SetTranscoderIp(TRANSCODER_IP, INET6_ADDRSTRLEN);
|
||||
#endif
|
||||
|
||||
std::cout << "Starting " << callsign << " " << g_Version << std::endl;
|
||||
|
||||
// and let it run
|
||||
if ( !g_Reflector.Start() )
|
||||
if (g_Reflector.Start())
|
||||
{
|
||||
std::cout << "Error starting reflector" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::cout << "Reflector " << g_Reflector.GetCallsign() << "started and listening" << std::endl;
|
||||
std::cout << "Reflector " << callsign << " started and listening" << std::endl;
|
||||
|
||||
// write new pid file
|
||||
std::ofstream ofs(PIDFILE_PATH, std::ofstream::out);
|
||||
std::ofstream ofs(pidpath, std::ofstream::out);
|
||||
ofs << getpid() << std::endl;
|
||||
ofs.close();
|
||||
|
||||
@@ -74,3 +77,132 @@ int main()
|
||||
// done
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#else // UTILITY is defined
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// global objects
|
||||
|
||||
SJsonKeys g_Keys;
|
||||
CConfigure g_Configure;
|
||||
CLookupDmr g_LDid;
|
||||
CLookupNxdn g_LNid;
|
||||
CLookupYsf g_LYtr;
|
||||
|
||||
static void usage(std::ostream &os, const char *name)
|
||||
{
|
||||
os << "\nUsage: " << name << " DATABASE SOURCE ACTION INIFILE\n";
|
||||
os << "DATABASE (choose one)\n"
|
||||
" dmr : The DmrId <==> Callsign databases.\n"
|
||||
" nxdn : The NxdnId <==> Callsign databases.\n"
|
||||
" ysf : The Callsign => Tx/Rx frequency database.\n"
|
||||
"SOURCE (choose one)\n"
|
||||
" file : The file specified by the FilePath ini parameter.\n"
|
||||
" http : The URL specified by the URL ini paramater.\n"
|
||||
"ACTION (choose one)\n"
|
||||
" print : Print all lines from the SOURCE that are syntactically correct.\n"
|
||||
" error : Print only the lines with failed syntax.\n"
|
||||
"INIFILE : an error-free urfd ini file (check it first with inicheck).\n\n"
|
||||
"Only the first character of DATABASE, SOURCE and ACTION is read.\n"
|
||||
"Example: " << name << " y f e urfd.ini # Check your YSF Tx/Rx database file specifed in urfd.ini for syntax errors.\n\n";
|
||||
}
|
||||
|
||||
enum class Edb { none, dmr, nxdn, ysf };
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Edb db;
|
||||
Eaction action;
|
||||
Esource source;
|
||||
|
||||
if (5 != argc)
|
||||
{
|
||||
usage(std::cerr, argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
switch (argv[1][0])
|
||||
{
|
||||
case 'd':
|
||||
case 'D':
|
||||
db = Edb::dmr;
|
||||
break;
|
||||
case 'n':
|
||||
case 'N':
|
||||
db = Edb::nxdn;
|
||||
break;
|
||||
|
||||
case 'y':
|
||||
case 'Y':
|
||||
db = Edb::ysf;
|
||||
break;
|
||||
|
||||
default:
|
||||
std::cout << "Unrecognized DATABASE: " << argv[1];
|
||||
db = Edb::none;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (argv[2][0])
|
||||
{
|
||||
case 'h':
|
||||
case 'H':
|
||||
source = Esource::http;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
case 'F':
|
||||
source = Esource::file;
|
||||
break;
|
||||
|
||||
default:
|
||||
std::cerr << "Unrecognized SOURCE: " << argv[2] << std::endl;
|
||||
db = Edb::none;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (argv[3][0])
|
||||
{
|
||||
case 'p':
|
||||
case 'P':
|
||||
action = Eaction::parse;
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
case 'E':
|
||||
action = Eaction::error_only;
|
||||
break;
|
||||
|
||||
default:
|
||||
std::cerr << "Unrecognized ACTION: " << argv[3] << std::endl;
|
||||
db = Edb::none;
|
||||
break;
|
||||
}
|
||||
|
||||
if (db == Edb::none)
|
||||
{
|
||||
usage(std::cerr, argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (g_Configure.ReadData(argv[4]))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
switch (db)
|
||||
{
|
||||
case Edb::dmr:
|
||||
g_LDid.Utility(action, source);
|
||||
break;
|
||||
|
||||
case Edb::nxdn:
|
||||
g_LNid.Utility(action, source);
|
||||
break;
|
||||
|
||||
case Edb::ysf:
|
||||
g_LYtr.Utility(action, source);
|
||||
break;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
+23
-45
@@ -18,78 +18,56 @@
|
||||
# if you change these locations, make sure the sgs.service file is updated!
|
||||
# you will also break hard coded paths in the dashboard file, index.php.
|
||||
|
||||
include configure.mk
|
||||
EXE = urfd
|
||||
|
||||
# if you make changed in these two variable, you'll need to change things
|
||||
# in the main.h file as well as the systemd service file.
|
||||
BINDIR = /usr/local/bin
|
||||
CFGDIR = /usr/local/etc
|
||||
INICHECK = inicheck
|
||||
|
||||
CC = g++
|
||||
DBUTIL = dbutil
|
||||
|
||||
include urfd.mk
|
||||
|
||||
ifeq ($(debug), true)
|
||||
CFLAGS = -ggdb3 -W -Werror -Wno-psabi -c -std=c++11 -MMD -MD -c
|
||||
CFLAGS = -ggdb3 -DDEBUG -W -Werror -std=c++11 -MMD -MD
|
||||
else
|
||||
CFLAGS = -c -W -Werror -Wno-psabi -std=c++11 -MMD -MD -c
|
||||
CFLAGS = -W -Werror -std=c++11 -MMD -MD
|
||||
endif
|
||||
|
||||
LDFLAGS=-pthread
|
||||
|
||||
URFSRCS = Buffer.cpp Callsign.cpp CallsignList.cpp CallsignListItem.cpp Client.cpp Clients.cpp DCSClient.cpp DCSProtocol.cpp DExtraClient.cpp DExtraPeer.cpp DExtraProtocol.cpp DPlusClient.cpp DPlusProtocol.cpp DVFramePacket.cpp DVHeaderPacket.cpp GateKeeper.cpp IP.cpp Notification.cpp Packet.cpp PacketStream.cpp PeerCallsignList.cpp Peer.cpp Peers.cpp Protocol.cpp Protocols.cpp Reflector.cpp SEProtocol.cpp UDPSocket.cpp User.cpp Users.cpp Version.cpp Main.cpp BMClient.cpp BMPeer.cpp BMProtocol.cpp BPTC19696.cpp CRC.cpp DMRIdDir.cpp DMRIdDirFile.cpp DMRIdDirHttp.cpp NXDNIdDir.cpp NXDNIdDirFile.cpp NXDNIdDirHttp.cpp DMRMMDVMClient.cpp DMRMMDVMProtocol.cpp DMRPlusClient.cpp DMRPlusProtocol.cpp Golay2087.cpp Golay24128.cpp Hamming.cpp M17Client.cpp M17CRC.cpp M17Packet.cpp M17Client.cpp M17Protocol.cpp NXDNClient.cpp NXDNProtocol.cpp P25Client.cpp P25Protocol.cpp QR1676.cpp RS129.cpp Semaphore.cpp USRPClient.cpp USRPProtocol.cpp Utils.cpp WiresXCmd.cpp WiresXCmdHandler.cpp WiresXInfo.cpp URFClient.cpp URFProtocol.cpp URFPeer.cpp YSFClient.cpp YSFConvolution.cpp YSFFich.cpp YSFNode.cpp YSFNodeDir.cpp YSFNodeDirFile.cpp YSFNodeDirHttp.cpp YSFPayload.cpp YSFProtocol.cpp YSFUtils.cpp
|
||||
|
||||
G3SRCS = G3Client.cpp G3Protocol.cpp RawSocket.cpp UDPMsgSocket.cpp
|
||||
|
||||
SRCS = $(URFSRCS)
|
||||
ifeq ($(use_g3), true)
|
||||
SRCS += $(G3SRCS)
|
||||
endif
|
||||
|
||||
ifeq ($(ysf_db), true)
|
||||
LDFLAGS += `mysql_config --libs`
|
||||
endif
|
||||
|
||||
ifdef tc_ip
|
||||
SRCS += CodecStream.cpp UnixDgramSocket.cpp
|
||||
endif
|
||||
LDFLAGS=-pthread -lcurl
|
||||
|
||||
SRCS = $(wildcard *.cpp)
|
||||
OBJS = $(SRCS:.cpp=.o)
|
||||
DEPS = $(SRCS:.cpp=.d)
|
||||
DBUTILOBJS = Configure.o CurlGet.o Lookup.o LookupDmr.o LookupNxdn.o LookupYsf.o YSFNode.o Callsign.o
|
||||
|
||||
EXE=urfd
|
||||
|
||||
all : $(EXE)
|
||||
all : $(EXE) $(INICHECK) $(DBUTIL)
|
||||
|
||||
$(EXE) : $(OBJS)
|
||||
$(CC) $^ -o $@ $(LDFLAGS)
|
||||
$(CXX) $^ -o $@ $(LDFLAGS)
|
||||
|
||||
$(INICHECK) : Configure.cpp CurlGet.o
|
||||
$(CXX) -DINICHECK $(CFLAGS) $< CurlGet.o -o $@ -lcurl
|
||||
|
||||
$(DBUTIL) : Main.cpp $(DBUTILOBJS)
|
||||
$(CXX) -DUTILITY $(CFLAGS) $< $(DBUTILOBJS) -o $@ -pthread -lcurl
|
||||
|
||||
%.o : %.cpp
|
||||
g++ $(CFLAGS) $< -o $@
|
||||
$(CXX) $(CFLAGS) -c $< -o $@
|
||||
|
||||
clean :
|
||||
$(RM) *.o *.d urfd
|
||||
$(RM) *.o *.d $(EXE) $(INICHECK) $(DBUTIL)
|
||||
|
||||
-include $(DEPS)
|
||||
|
||||
install :
|
||||
ln -f -s $(shell pwd)/$(EXE).blacklist $(CFGDIR)/$(EXE).blacklist
|
||||
ln -f -s $(shell pwd)/$(EXE).whitelist $(CFGDIR)/$(EXE).whitelist
|
||||
ln -f -s $(shell pwd)/$(EXE).interlink $(CFGDIR)/$(EXE).interlink
|
||||
ifeq ($(use_g3), true)
|
||||
ln -f -s $(shell pwd)/$(EXE).terminal $(CFGDIR)/$(EXE).terminal
|
||||
endif
|
||||
cp -f ../systemd/$(EXE).service /etc/systemd/system/
|
||||
cp -f $(EXE).service /etc/systemd/system/
|
||||
cp -f $(EXE) $(BINDIR)
|
||||
systemctl enable $(EXE).service
|
||||
systemctl daemon-reload
|
||||
systemctl start $(EXE)
|
||||
|
||||
uninstall :
|
||||
rm -f $(CFGDIR)/$(EXE).blacklist
|
||||
rm -f $(CFGDIR)/$(EXE).whitelist
|
||||
rm -f $(CFGDIR)/$(EXE).interlink
|
||||
rm -f $(CFGDIR)/$(EXE).terminal
|
||||
systemctl stop $(EXE).service
|
||||
rm -f $(CFGDIR)/dmrid.dat
|
||||
systemctl disable $(EXE).service
|
||||
rm -f /etc/systemd/system/$(EXE).service
|
||||
$(RM) /etc/systemd/system/$(EXE).service
|
||||
systemctl daemon-reload
|
||||
$(RM) $(BINDIR)/$(EXE)
|
||||
@@ -17,7 +17,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
|
||||
#include "NXDNClient.h"
|
||||
|
||||
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Defines.h"
|
||||
#include "Client.h"
|
||||
|
||||
class CNXDNClient : public CClient
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
|
||||
// urfd -- The universal reflector
|
||||
// Copyright © 2021 Thomas A. Early N7TAE
|
||||
//
|
||||
// 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 3 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, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <string.h>
|
||||
#include "Main.h"
|
||||
#include "Reflector.h"
|
||||
#include "NXDNIdDir.h"
|
||||
#include "NXDNIdDirFile.h"
|
||||
#include "NXDNIdDirHttp.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor & destructor
|
||||
|
||||
CNXDNidDir::CNXDNidDir()
|
||||
{
|
||||
keep_running = true;
|
||||
}
|
||||
|
||||
CNXDNidDir::~CNXDNidDir()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// init & close
|
||||
|
||||
bool CNXDNidDir::Init(void)
|
||||
{
|
||||
// load content
|
||||
Reload();
|
||||
|
||||
// reset run flag
|
||||
keep_running = true;
|
||||
|
||||
// start thread;
|
||||
m_Future = std::async(std::launch::async, &CNXDNidDir::Thread, this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CNXDNidDir::Close(void)
|
||||
{
|
||||
keep_running = false;
|
||||
if ( m_Future.valid() )
|
||||
{
|
||||
m_Future.get();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// thread
|
||||
|
||||
void CNXDNidDir::Thread()
|
||||
{
|
||||
while (keep_running)
|
||||
{
|
||||
// Wait DMRIDDB_REFRESH_RATE minutes
|
||||
for (int i=0; i<30*NXDNIDDB_REFRESH_RATE && keep_running; i++)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
|
||||
|
||||
// have lists files changed ?
|
||||
if ( NeedReload() )
|
||||
{
|
||||
Reload();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Reload
|
||||
|
||||
bool CNXDNidDir::Reload(void)
|
||||
{
|
||||
CBuffer buffer;
|
||||
bool ok = false;
|
||||
|
||||
if ( LoadContent(&buffer) )
|
||||
{
|
||||
Lock();
|
||||
{
|
||||
ok = RefreshContent(buffer);
|
||||
}
|
||||
Unlock();
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// find
|
||||
|
||||
const CCallsign *CNXDNidDir::FindCallsign(uint16_t nxdnid)
|
||||
{
|
||||
auto found = m_CallsignMap.find(nxdnid);
|
||||
if ( found != m_CallsignMap.end() )
|
||||
{
|
||||
return &(found->second);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint16_t CNXDNidDir::FindNXDNid(const CCallsign &callsign)
|
||||
{
|
||||
auto found = m_NXDNidMap.find(callsign);
|
||||
if ( found != m_NXDNidMap.end() )
|
||||
{
|
||||
return (found->second);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// syntax helpers
|
||||
|
||||
bool CNXDNidDir::IsValidNXDNid(const char *sz)
|
||||
{
|
||||
bool ok = false;
|
||||
size_t n = ::strlen(sz);
|
||||
if ( (n > 0) && (n <= 5) )
|
||||
{
|
||||
ok = true;
|
||||
for ( size_t i = 0; (i < n) && ok; i++ )
|
||||
{
|
||||
ok &= ::isdigit(sz[i]);
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
|
||||
// urfd -- The universal reflector
|
||||
// Copyright © 2021 Thomas A. Early N7TAE
|
||||
// Copyright © 2021 Doug McLain AD8DP
|
||||
//
|
||||
// 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 3 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, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include "Buffer.h"
|
||||
#include "Callsign.h"
|
||||
|
||||
// compare function for std::map::find
|
||||
|
||||
struct CNXDNidDirCallsignCompare
|
||||
{
|
||||
bool operator() (const CCallsign &cs1, const CCallsign &cs2) const
|
||||
{ return cs1.HasLowerCallsign(cs2);}
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CNXDNidDir
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CNXDNidDir();
|
||||
|
||||
// destructor
|
||||
~CNXDNidDir();
|
||||
|
||||
// init & close
|
||||
virtual bool Init(void);
|
||||
virtual void Close(void);
|
||||
|
||||
// locks
|
||||
void Lock(void) { m_Mutex.lock(); }
|
||||
void Unlock(void) { m_Mutex.unlock(); }
|
||||
|
||||
// refresh
|
||||
virtual bool LoadContent(CBuffer *) { return false; }
|
||||
virtual bool RefreshContent(const CBuffer &) { return false; }
|
||||
|
||||
// find
|
||||
const CCallsign *FindCallsign(uint16_t);
|
||||
uint16_t FindNXDNid(const CCallsign &);
|
||||
|
||||
protected:
|
||||
// thread
|
||||
void Thread();
|
||||
|
||||
// reload helpers
|
||||
bool Reload(void);
|
||||
virtual bool NeedReload(void) { return false; }
|
||||
bool IsValidNXDNid(const char *);
|
||||
|
||||
protected:
|
||||
// data
|
||||
std::map <uint16_t, CCallsign> m_CallsignMap;
|
||||
std::map <CCallsign, uint16_t, CNXDNidDirCallsignCompare> m_NXDNidMap;
|
||||
|
||||
// Lock()
|
||||
std::mutex m_Mutex;
|
||||
|
||||
// thread
|
||||
std::atomic<bool> keep_running;
|
||||
std::future<void> m_Future;
|
||||
|
||||
};
|
||||
@@ -1,159 +0,0 @@
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
|
||||
// urfd -- The universal reflector
|
||||
// Copyright © 2021 Thomas A. Early N7TAE
|
||||
//
|
||||
// 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 3 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, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include "Main.h"
|
||||
#include "NXDNIdDirFile.h"
|
||||
|
||||
|
||||
#if (NXDNIDDB_USE_RLX_SERVER == 0)
|
||||
CNXDNidDirFile g_NXDNidDir;
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor & destructor
|
||||
|
||||
CNXDNidDirFile::CNXDNidDirFile()
|
||||
{
|
||||
memset(&m_LastModTime, 0, sizeof(time_t));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// init & close
|
||||
|
||||
bool CNXDNidDirFile::Init(void)
|
||||
{
|
||||
return CNXDNidDir::Init();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// refresh
|
||||
|
||||
bool CNXDNidDirFile::NeedReload(void)
|
||||
{
|
||||
bool needReload = false;
|
||||
|
||||
time_t time;
|
||||
if ( GetLastModTime(&time) )
|
||||
{
|
||||
needReload = time != m_LastModTime;
|
||||
}
|
||||
return needReload;
|
||||
}
|
||||
|
||||
bool CNXDNidDirFile::LoadContent(CBuffer *buffer)
|
||||
{
|
||||
bool ok = false;
|
||||
std::ifstream file;
|
||||
std::streampos size;
|
||||
|
||||
// open file
|
||||
file.open(NXDNIDDB_PATH, std::ios::in | std::ios::binary | std::ios::ate);
|
||||
if ( file.is_open() )
|
||||
{
|
||||
// read file
|
||||
size = file.tellg();
|
||||
if ( size > 0 )
|
||||
{
|
||||
// read file into buffer
|
||||
buffer->resize((int)size+1);
|
||||
file.seekg (0, std::ios::beg);
|
||||
file.read((char *)buffer->data(), (int)size);
|
||||
|
||||
// close file
|
||||
file.close();
|
||||
|
||||
// update time
|
||||
GetLastModTime(&m_LastModTime);
|
||||
|
||||
// done
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
// done
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool CNXDNidDirFile::RefreshContent(const CBuffer &buffer)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
// clear directory
|
||||
m_CallsignMap.clear();
|
||||
m_NXDNidMap.clear();
|
||||
|
||||
// scan buffer
|
||||
if ( buffer.size() > 0 )
|
||||
{
|
||||
// crack it
|
||||
char *ptr1 = (char *)buffer.data();
|
||||
char *ptr2;
|
||||
|
||||
// get next line
|
||||
while ( (ptr2 = ::strchr(ptr1, '\n')) != nullptr )
|
||||
{
|
||||
*ptr2 = 0;
|
||||
// get items
|
||||
char *nxdnid;
|
||||
char *callsign;
|
||||
if ( ((nxdnid = ::strtok(ptr1, ",")) != nullptr) && IsValidNXDNid(nxdnid) )
|
||||
{
|
||||
if ( ((callsign = ::strtok(nullptr, ",")) != nullptr) )
|
||||
{
|
||||
// new entry
|
||||
uint16_t us = atoi(nxdnid);
|
||||
CCallsign cs(callsign, 0, us);
|
||||
if ( cs.IsValid() )
|
||||
{
|
||||
m_CallsignMap.insert(std::pair<uint32_t,CCallsign>(us, cs));
|
||||
m_NXDNidMap.insert(std::pair<CCallsign,uint32_t>(cs,us));
|
||||
}
|
||||
}
|
||||
}
|
||||
// next line
|
||||
ptr1 = ptr2+1;
|
||||
}
|
||||
|
||||
// done
|
||||
ok = true;
|
||||
}
|
||||
|
||||
// report
|
||||
std::cout << "Read " << m_NXDNidMap.size() << " NXDN ids from file " << NXDNIDDB_PATH << std::endl;
|
||||
|
||||
// done
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
bool CNXDNidDirFile::GetLastModTime(time_t *time)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
struct stat fileStat;
|
||||
if( ::stat(NXDNIDDB_PATH, &fileStat) != -1 )
|
||||
{
|
||||
*time = fileStat.st_mtime;
|
||||
ok = true;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
@@ -1,177 +0,0 @@
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
|
||||
// urfd -- The universal reflector
|
||||
// Copyright © 2021 Thomas A. Early N7TAE
|
||||
//
|
||||
// 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 3 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, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <string.h>
|
||||
#include "Main.h"
|
||||
#include "Reflector.h"
|
||||
#include "NXDNIdDirHttp.h"
|
||||
|
||||
#if (NXDNIDDB_USE_RLX_SERVER == 1)
|
||||
CNXDNidDirHttp g_NXDNidDir;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// refresh
|
||||
|
||||
bool CNXDNidDirHttp::LoadContent(CBuffer *buffer)
|
||||
{
|
||||
// get file from xlxapi server
|
||||
return HttpGet("www.dudetronics.com", "ar-dns/NXDN.csv", 80, buffer);
|
||||
}
|
||||
|
||||
bool CNXDNidDirHttp::RefreshContent(const CBuffer &buffer)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
// clear directory
|
||||
m_CallsignMap.clear();
|
||||
m_NXDNidMap.clear();
|
||||
|
||||
// scan file
|
||||
if ( buffer.size() > 0 )
|
||||
{
|
||||
char *ptr1 = (char *)buffer.data();
|
||||
char *ptr2;
|
||||
// get next line
|
||||
while ( (ptr2 = ::strchr(ptr1, '\n')) != nullptr )
|
||||
{
|
||||
std::cout << "newline: " << std::string(ptr2) << std::endl;
|
||||
*ptr2 = 0;
|
||||
// get items
|
||||
char *nxdnid;
|
||||
char *callsign;
|
||||
if ( ((nxdnid = ::strtok(ptr1, ",")) != nullptr) && IsValidNXDNid(nxdnid) )
|
||||
{
|
||||
if ( ((callsign = ::strtok(nullptr, ",")) != nullptr) )
|
||||
{
|
||||
// new entry
|
||||
uint16_t us = atoi(nxdnid);
|
||||
CCallsign cs(callsign, 0, us);
|
||||
if ( cs.IsValid() )
|
||||
{
|
||||
m_CallsignMap.insert(std::pair<uint16_t,CCallsign>(us, cs));
|
||||
m_NXDNidMap.insert(std::pair<CCallsign,uint16_t>(cs,us));
|
||||
}
|
||||
}
|
||||
}
|
||||
// next line
|
||||
ptr1 = ptr2+1;
|
||||
}
|
||||
// done
|
||||
ok = true;
|
||||
}
|
||||
|
||||
// report
|
||||
std::cout << "Read " << m_NXDNidMap.size() << " NXDN ids from xlxapi.rlx.lu database " << std::endl;
|
||||
|
||||
// done
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// httpd helpers
|
||||
|
||||
#define NXDNID_HTTPGET_SIZEMAX (256)
|
||||
|
||||
bool CNXDNidDirHttp::HttpGet(const char *hostname, const char *filename, int port, CBuffer *buffer)
|
||||
{
|
||||
bool ok = false;
|
||||
int sock_id;
|
||||
|
||||
// open socket
|
||||
if ( (sock_id = ::socket(AF_INET, SOCK_STREAM, 0)) >= 0 )
|
||||
{
|
||||
// get hostname address
|
||||
struct sockaddr_in servaddr;
|
||||
struct hostent *hp;
|
||||
memset(&servaddr,0,sizeof(servaddr));
|
||||
if( (hp = gethostbyname(hostname)) != nullptr )
|
||||
{
|
||||
// dns resolved
|
||||
memcpy((char *)&servaddr.sin_addr.s_addr, (char *)hp->h_addr, hp->h_length);
|
||||
servaddr.sin_port = htons(port);
|
||||
servaddr.sin_family = AF_INET;
|
||||
|
||||
// connect
|
||||
if ( ::connect(sock_id, (struct sockaddr *)&servaddr, sizeof(servaddr)) == 0)
|
||||
{
|
||||
// send the GET request
|
||||
char request[NXDNID_HTTPGET_SIZEMAX];
|
||||
::sprintf(request, "GET /%s HTTP/1.0\r\nFrom: %s\r\nUser-Agent: urfd\r\n\r\n",
|
||||
filename, (const char *)g_Reflector.GetCallsign());
|
||||
::write(sock_id, request, strlen(request));
|
||||
|
||||
// config receive timeouts
|
||||
fd_set read_set;
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 5;
|
||||
timeout.tv_usec = 0;
|
||||
FD_ZERO(&read_set);
|
||||
FD_SET(sock_id, &read_set);
|
||||
|
||||
// get the reply back
|
||||
buffer->clear();
|
||||
bool done = false;
|
||||
do
|
||||
{
|
||||
char buf[1440];
|
||||
ssize_t len = 0;
|
||||
select(sock_id+1, &read_set, nullptr, nullptr, &timeout);
|
||||
//if ( (ret > 0) || ((ret < 0) && (errno == EINPROGRESS)) )
|
||||
//if ( ret >= 0 )
|
||||
//{
|
||||
usleep(5000);
|
||||
len = read(sock_id, buf, 1440);
|
||||
if ( len > 0 )
|
||||
{
|
||||
buffer->Append((uint8_t *)buf, (int)len);
|
||||
ok = true;
|
||||
}
|
||||
//}
|
||||
done = (len <= 0);
|
||||
|
||||
}
|
||||
while (!done);
|
||||
buffer->Append((uint8_t)0);
|
||||
|
||||
// and disconnect
|
||||
close(sock_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Cannot establish connection with host " << hostname << std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Host " << hostname << " not found" << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Failed to open wget socket" << std::endl;
|
||||
}
|
||||
|
||||
// done
|
||||
return ok;
|
||||
}
|
||||
+30
-31
@@ -17,14 +17,13 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "NXDNClient.h"
|
||||
#include "NXDNProtocol.h"
|
||||
#include "YSFDefines.h"
|
||||
#include "Reflector.h"
|
||||
#include "GateKeeper.h"
|
||||
#include "Golay24128.h"
|
||||
#include "Global.h"
|
||||
|
||||
const uint8_t NXDN_LICH_RFCT_RDCH = 2U;
|
||||
const uint8_t NXDN_LICH_USC_SACCH_NS = 0U;
|
||||
@@ -53,6 +52,10 @@ CNXDNProtocol::CNXDNProtocol()
|
||||
|
||||
bool CNXDNProtocol::Initialize(const char *type, const EProtocol ptype, const uint16_t port, const bool has_ipv4, const bool has_ipv6)
|
||||
{
|
||||
// config value
|
||||
m_ReflectorId = g_Configure.GetUnsigned(g_Keys.nxdn.reflectorid);
|
||||
m_AutolinkModule = g_Configure.GetAutolinkModule(g_Keys.nxdn.autolinkmod);
|
||||
|
||||
// base class
|
||||
if (! CProtocol::Initialize(type, ptype, port, has_ipv4, has_ipv6))
|
||||
return false;
|
||||
@@ -130,9 +133,8 @@ void CNXDNProtocol::Task(void)
|
||||
auto newclient = std::make_shared<CNXDNClient>(Callsign, Ip);
|
||||
|
||||
// aautolink, if enabled
|
||||
#if NXDN_AUTOLINK_ENABLE
|
||||
newclient->SetReflectorModule(NXDN_AUTOLINK_MODULE);
|
||||
#endif
|
||||
if (m_AutolinkModule)
|
||||
newclient->SetReflectorModule(m_AutolinkModule);
|
||||
|
||||
// and append
|
||||
clients->AddClient(newclient);
|
||||
@@ -141,7 +143,7 @@ void CNXDNProtocol::Task(void)
|
||||
{
|
||||
client->Alive();
|
||||
}
|
||||
|
||||
|
||||
// acknowledge the request -- NXDNReflector simply echoes the packet
|
||||
Send(Buffer, Ip);
|
||||
// and done
|
||||
@@ -244,11 +246,10 @@ void CNXDNProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
|
||||
|
||||
void CNXDNProtocol::HandleQueue(void)
|
||||
{
|
||||
m_Queue.Lock();
|
||||
while ( !m_Queue.empty() )
|
||||
while (! m_Queue.IsEmpty())
|
||||
{
|
||||
// get the packet
|
||||
auto packet = m_Queue.pop();
|
||||
auto packet = m_Queue.Pop();
|
||||
|
||||
// get our sender's id
|
||||
const auto mod = packet->GetPacketModule();
|
||||
@@ -308,7 +309,6 @@ void CNXDNProtocol::HandleQueue(void)
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
}
|
||||
m_Queue.Unlock();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -408,24 +408,24 @@ bool CNXDNProtocol::IsValidDvFramePacket(const CIp &Ip, const CBuffer &Buffer, s
|
||||
rpt1.SetCSModule(NXDN_MODULE_ID);
|
||||
rpt2.SetCSModule(' ');
|
||||
header = std::unique_ptr<CDvHeaderPacket>(new CDvHeaderPacket(csMY, CCallsign("CQCQCQ"), rpt1, rpt2, m_uiStreamId, false));
|
||||
|
||||
|
||||
if ( g_GateKeeper.MayTransmit(header->GetMyCallsign(), Ip, EProtocol::nxdn, header->GetRpt2Module()) )
|
||||
{
|
||||
OnDvHeaderPacketIn(header, Ip);
|
||||
OnDvHeaderPacketIn(header, Ip);
|
||||
}
|
||||
}
|
||||
|
||||
// get DV frames
|
||||
uint8_t ambe49[7];
|
||||
|
||||
|
||||
uint8_t ambe0[9];
|
||||
uint8_t ambe1[9];
|
||||
uint8_t ambe2[9];
|
||||
uint8_t ambe3[9];
|
||||
|
||||
|
||||
memcpy(ambe49, Buffer.data() + 15, 7);
|
||||
encode(ambe49, ambe0);
|
||||
|
||||
|
||||
uint8_t t[7];
|
||||
const uint8_t *d = &(Buffer.data()[21]);
|
||||
for(int i = 0; i < 6; ++i){
|
||||
@@ -436,10 +436,10 @@ bool CNXDNProtocol::IsValidDvFramePacket(const CIp &Ip, const CBuffer &Buffer, s
|
||||
|
||||
memcpy(ambe49, t, 7);
|
||||
encode(ambe49, ambe1);
|
||||
|
||||
|
||||
memcpy(ambe49, Buffer.data() + 29, 7);
|
||||
encode(ambe49, ambe2);
|
||||
|
||||
|
||||
d = &(Buffer.data()[35]);
|
||||
for(int i = 0; i < 6; ++i){
|
||||
t[i] = d[i] << 1;
|
||||
@@ -479,15 +479,15 @@ bool CNXDNProtocol::EncodeNXDNHeaderPacket(const CDvHeaderPacket &Header, CBuffe
|
||||
{
|
||||
Buffer.resize(43);
|
||||
uint16_t NXDNId = Header.GetMyCallsign().GetNXDNid();
|
||||
uint16_t RptrId = NXDN_REFID;
|
||||
|
||||
uint16_t RptrId = m_ReflectorId;
|
||||
|
||||
memcpy(Buffer.data(), "NXDND", 5);
|
||||
Buffer.data()[5U] = (NXDNId >> 8) & 0xFFU;
|
||||
Buffer.data()[6U] = (NXDNId >> 0) & 0xFFU;
|
||||
Buffer.data()[7U] = (RptrId >> 8) & 0xFFU;
|
||||
Buffer.data()[8U] = (RptrId >> 0) & 0xFFU;
|
||||
Buffer.data()[9U] = 0x01U;
|
||||
|
||||
|
||||
const uint8_t idle[3U] = {0x10, 0x00, 0x00};
|
||||
m_lich = 0;
|
||||
memset(m_sacch, 0, 5U);
|
||||
@@ -514,7 +514,7 @@ bool CNXDNProtocol::EncodeNXDNHeaderPacket(const CDvHeaderPacket &Header, CBuffe
|
||||
set_layer3_blks(0U);
|
||||
memcpy(&Buffer.data()[15U], m_layer3, 14U);
|
||||
memcpy(&Buffer.data()[29U], m_layer3, 14U);
|
||||
|
||||
|
||||
if (Buffer.data()[10U] == 0x81U || Buffer.data()[10U] == 0x83U) {
|
||||
Buffer.data()[9U] |= Buffer.data()[15U] == 0x01U ? 0x04U : 0x00U;
|
||||
Buffer.data()[9U] |= Buffer.data()[15U] == 0x08U ? 0x08U : 0x00U;
|
||||
@@ -526,7 +526,7 @@ bool CNXDNProtocol::EncodeNXDNHeaderPacket(const CDvHeaderPacket &Header, CBuffe
|
||||
Buffer.data()[9U] |= Buffer.data()[12U] == 0x08U ? 0x08U : 0x00U;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -535,15 +535,15 @@ bool CNXDNProtocol::EncodeNXDNPacket(const CDvHeaderPacket &Header, uint32_t seq
|
||||
uint8_t ambe[28];
|
||||
Buffer.resize(43);
|
||||
uint16_t NXDNId = Header.GetMyCallsign().GetNXDNid();
|
||||
uint16_t RptrId = NXDN_REFID;
|
||||
|
||||
uint16_t RptrId = m_ReflectorId;
|
||||
|
||||
memcpy(Buffer.data(), "NXDND", 5);
|
||||
Buffer.data()[5U] = (NXDNId >> 8) & 0xFFU;
|
||||
Buffer.data()[6U] = (NXDNId >> 0) & 0xFFU;
|
||||
Buffer.data()[7U] = (RptrId >> 8) & 0xFFU;
|
||||
Buffer.data()[8U] = (RptrId >> 0) & 0xFFU;
|
||||
Buffer.data()[9U] = 0x01U;
|
||||
|
||||
|
||||
uint8_t msg[3U];
|
||||
m_lich = 0;
|
||||
memset(m_sacch, 0, 5U);
|
||||
@@ -590,7 +590,7 @@ bool CNXDNProtocol::EncodeNXDNPacket(const CDvHeaderPacket &Header, uint32_t seq
|
||||
for(int i = 0; i < 4; ++i){
|
||||
decode(DvFrames[i].GetCodecData(ECodecType::dmr), ambe+(i*7));
|
||||
}
|
||||
|
||||
|
||||
memcpy(&Buffer.data()[15], ambe, 7);
|
||||
for(int i = 0; i < 7; ++i){
|
||||
Buffer.data()[21+i] |= (ambe[7+i] >> 1);
|
||||
@@ -604,7 +604,7 @@ bool CNXDNProtocol::EncodeNXDNPacket(const CDvHeaderPacket &Header, uint32_t seq
|
||||
Buffer.data()[36+i] = (ambe[21+i] & 1) << 7;
|
||||
}
|
||||
Buffer.data()[41] |= (ambe[27] >> 2);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -657,11 +657,11 @@ void CNXDNProtocol::decode(const unsigned char* in, unsigned char* out) const
|
||||
|
||||
void CNXDNProtocol::encode(const unsigned char* in, unsigned char* out) const
|
||||
{
|
||||
|
||||
|
||||
unsigned int aOrig = 0U;
|
||||
unsigned int bOrig = 0U;
|
||||
unsigned int cOrig = 0U;
|
||||
|
||||
|
||||
unsigned int MASK = 0x000800U;
|
||||
for (unsigned int i = 0U; i < 12U; i++, MASK >>= 1) {
|
||||
unsigned int n1 = i + 0U;
|
||||
@@ -838,4 +838,3 @@ void CNXDNProtocol::encode_crc6(uint8_t *d, uint8_t len)
|
||||
WRITE_BIT(d, n, b);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Defines.h"
|
||||
#include "Timer.h"
|
||||
#include "Protocol.h"
|
||||
#include "DVHeaderPacket.h"
|
||||
@@ -80,10 +81,10 @@ protected:
|
||||
|
||||
// uiStreamId helpers
|
||||
uint32_t IpToStreamId(const CIp &) const;
|
||||
|
||||
|
||||
void encode(const unsigned char*, unsigned char*) const;
|
||||
void decode(const unsigned char*, unsigned char*) const;
|
||||
|
||||
|
||||
uint8_t get_lich_fct(uint8_t);
|
||||
void set_lich_rfct(uint8_t);
|
||||
void set_lich_fct(uint8_t);
|
||||
@@ -121,4 +122,7 @@ protected:
|
||||
uint8_t m_lich;
|
||||
uint8_t m_sacch[5];
|
||||
uint8_t m_layer3[22];
|
||||
|
||||
uint16_t m_ReflectorId;
|
||||
char m_AutolinkModule;
|
||||
};
|
||||
@@ -16,7 +16,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
|
||||
#include "Notification.h"
|
||||
|
||||
CNotification::CNotification()
|
||||
|
||||
@@ -32,12 +32,6 @@
|
||||
class CNotificationQueue
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CNotificationQueue() {}
|
||||
|
||||
// destructor
|
||||
~CNotificationQueue() {}
|
||||
|
||||
// lock
|
||||
void Lock() { m_Mutex.lock(); }
|
||||
void Unlock() { m_Mutex.unlock(); }
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
|
||||
#include "P25Client.h"
|
||||
|
||||
|
||||
|
||||
@@ -18,8 +18,9 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Defines.h"
|
||||
#include "Client.h"
|
||||
|
||||
class CP25Client : public CClient
|
||||
{
|
||||
public:
|
||||
|
||||
+21
-22
@@ -17,13 +17,12 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "P25Client.h"
|
||||
#include "P25Protocol.h"
|
||||
|
||||
#include "Reflector.h"
|
||||
#include "GateKeeper.h"
|
||||
#include "Global.h"
|
||||
|
||||
const uint8_t REC62[] = {0x62U, 0x02U, 0x02U, 0x0CU, 0x0BU, 0x12U, 0x64U, 0x00U, 0x00U, 0x80U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,0x00U, 0x00U, 0x00U, 0x00U, 0x00U};
|
||||
const uint8_t REC63[] = {0x63U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U};
|
||||
@@ -50,6 +49,11 @@ const uint8_t REC80[] = {0x80U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
|
||||
|
||||
bool CP25Protocol::Initialize(const char *type, const EProtocol ptype, const uint16_t port, const bool has_ipv4, const bool has_ipv6)
|
||||
{
|
||||
// config data
|
||||
m_ReflectorId = g_Configure.GetUnsigned(g_Keys.p25.reflectorid);
|
||||
m_DefaultId = g_Configure.GetUnsigned(g_Keys.mmdvm.defaultid);
|
||||
m_AutolinkModule = g_Configure.GetAutolinkModule(g_Keys.p25.autolinkmod);
|
||||
|
||||
m_uiStreamId = 0;
|
||||
// base class
|
||||
if (! CProtocol::Initialize(type, ptype, port, has_ipv4, has_ipv6))
|
||||
@@ -118,9 +122,8 @@ void CP25Protocol::Task(void)
|
||||
auto newclient = std::make_shared<CP25Client>(Callsign, Ip);
|
||||
|
||||
// aautolink, if enabled
|
||||
#if P25_AUTOLINK_ENABLE
|
||||
newclient->SetReflectorModule(P25_AUTOLINK_MODULE);
|
||||
#endif
|
||||
if (m_AutolinkModule)
|
||||
newclient->SetReflectorModule(m_AutolinkModule);
|
||||
|
||||
// and append
|
||||
clients->AddClient(newclient);
|
||||
@@ -129,7 +132,7 @@ void CP25Protocol::Task(void)
|
||||
{
|
||||
client->Alive();
|
||||
}
|
||||
|
||||
|
||||
// acknowledge the request -- P25Reflector simply echoes the packet
|
||||
Send(Buffer, Ip);
|
||||
// and done
|
||||
@@ -226,11 +229,10 @@ void CP25Protocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
|
||||
|
||||
void CP25Protocol::HandleQueue(void)
|
||||
{
|
||||
m_Queue.Lock();
|
||||
while ( !m_Queue.empty() )
|
||||
while (! m_Queue.IsEmpty())
|
||||
{
|
||||
// get the packet
|
||||
auto packet = m_Queue.pop();
|
||||
auto packet = m_Queue.Pop();
|
||||
|
||||
// get our sender's id
|
||||
const auto module = packet->GetPacketModule();
|
||||
@@ -273,7 +275,6 @@ void CP25Protocol::HandleQueue(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
m_Queue.Unlock();
|
||||
}
|
||||
|
||||
|
||||
@@ -308,7 +309,7 @@ bool CP25Protocol::IsValidDvPacket(const CIp &Ip, const CBuffer &Buffer, std::un
|
||||
{
|
||||
int offset = 0;
|
||||
bool last = false;
|
||||
|
||||
|
||||
switch (Buffer.data()[0U]) {
|
||||
case 0x62U:
|
||||
offset = 10U;
|
||||
@@ -357,7 +358,7 @@ bool CP25Protocol::IsValidDvPacket(const CIp &Ip, const CBuffer &Buffer, std::un
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
frame = std::unique_ptr<CDvFramePacket>(new CDvFramePacket(&(Buffer.data()[offset]), m_uiStreamId, last));
|
||||
return true;
|
||||
}
|
||||
@@ -387,19 +388,18 @@ bool CP25Protocol::IsValidDvHeaderPacket(const CIp &Ip, const CBuffer &Buffer, s
|
||||
void CP25Protocol::EncodeP25Packet(const CDvHeaderPacket &Header, const CDvFramePacket &DvFrame, uint32_t iSeq, CBuffer &Buffer, bool islast) const
|
||||
{
|
||||
uint32_t uiSrcId = Header.GetMyCallsign().GetDmrid();
|
||||
uint32_t uiRptrId = P25_REFID;
|
||||
|
||||
|
||||
if(uiSrcId == 0){
|
||||
uiSrcId = DMRMMDVM_DEFAULTID;
|
||||
uiSrcId = m_DefaultId;
|
||||
}
|
||||
|
||||
|
||||
if(islast)
|
||||
{
|
||||
Buffer.resize(17);
|
||||
::memcpy(Buffer.data(), REC80, 17U);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
switch (iSeq % 18) {
|
||||
case 0x00U:
|
||||
Buffer.resize(22);
|
||||
@@ -420,9 +420,9 @@ void CP25Protocol::EncodeP25Packet(const CDvHeaderPacket &Header, const CDvFrame
|
||||
Buffer.resize(17);
|
||||
::memcpy(Buffer.data(), REC65, 17U);
|
||||
::memcpy(Buffer.data() + 5U, DvFrame.GetCodecData(ECodecType::p25), 11U);
|
||||
Buffer.data()[1U] = (uiRptrId >> 16) & 0xFFU;
|
||||
Buffer.data()[2U] = (uiRptrId >> 8) & 0xFFU;
|
||||
Buffer.data()[3U] = (uiRptrId >> 0) & 0xFFU;
|
||||
Buffer.data()[1U] = (m_ReflectorId >> 16) & 0xFFU;
|
||||
Buffer.data()[2U] = (m_ReflectorId >> 8) & 0xFFU;
|
||||
Buffer.data()[3U] = (m_ReflectorId >> 0) & 0xFFU;
|
||||
break;
|
||||
case 0x04U:
|
||||
Buffer.resize(17);
|
||||
@@ -528,4 +528,3 @@ void CP25Protocol::HandleKeepalives(void)
|
||||
}
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Defines.h"
|
||||
#include "Timer.h"
|
||||
#include "Protocol.h"
|
||||
#include "DVHeaderPacket.h"
|
||||
@@ -53,7 +54,7 @@ protected:
|
||||
// queue helper
|
||||
void HandleQueue(void);
|
||||
void HandleKeepalives(void);
|
||||
|
||||
|
||||
// stream helpers
|
||||
void OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &, const CIp &);
|
||||
|
||||
@@ -72,4 +73,9 @@ protected:
|
||||
// for queue header caches
|
||||
std::unordered_map<char, CP25StreamCacheItem> m_StreamsCache;
|
||||
uint32_t m_uiStreamId;
|
||||
|
||||
// config data
|
||||
uint32_t m_ReflectorId;
|
||||
uint32_t m_DefaultId;
|
||||
char m_AutolinkModule;
|
||||
};
|
||||
@@ -16,7 +16,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Main.h"
|
||||
#include <iostream>
|
||||
#include "Packet.h"
|
||||
|
||||
// default constructor
|
||||
|
||||
+1
-6
@@ -40,13 +40,8 @@ public:
|
||||
CPacket(uint16_t sid, uint8_t dstarpid, uint8_t dmrpid, uint8_t dmrsubpid, uint8_t ysfpid, uint8_t ysfsubpid, uint8_t ysfsubpidmax, ECodecType, bool lastpacket);
|
||||
CPacket(const CM17Packet &);
|
||||
|
||||
// destructor
|
||||
virtual ~CPacket() {}
|
||||
|
||||
// virtual duplication
|
||||
virtual std::unique_ptr<CPacket> Duplicate(void) const = 0;
|
||||
|
||||
// identity
|
||||
virtual std::unique_ptr<CPacket> Copy(void) = 0;
|
||||
virtual bool IsDvHeader(void) const = 0;
|
||||
virtual bool IsDvFrame(void) const = 0;
|
||||
bool IsLastPacket(void) const { return m_bLastPacket; }
|
||||
|
||||
Loaded 100 of 155 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user